-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
release: 7.60.0 #22825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: stable
Are you sure you want to change the base?
release: 7.60.0 #22825
Conversation
## **Description** The header and header icons aren't aligned ## **Changelog** CHANGELOG entry:null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-196 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** `~` ### **Before** <img width="500" alt="before" src="https://github.com/user-attachments/assets/d158d2cf-8f31-44a6-aba2-1823cc3f5669" /> ### **After** <img width="500" alt="after" src="https://github.com/user-attachments/assets/62f27aa9-9b41-44ce-bf80-2367a2b1bedc" /> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Vertically centers the Wallet header content and sets a fixed 72px header height, updating snapshots accordingly. > > - **UI (Navbar)**: > - Add `innerStyles.headerContainer` in `app/components/UI/Navbar/index.js` with `height: 72` and `alignItems: 'center'`. > - Apply `style={innerStyles.headerContainer}` to `HeaderBase` in `getWalletNavbarOptions` to enforce alignment and height. > - **Tests**: > - Update Wallet view snapshots to reflect centered header and fixed height (`__snapshots__/index.test.tsx.snap`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 32279d4. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** This PR implements optimistic updates for Predict positions to provide immediate user feedback when placing BUY/SELL orders, significantly improving the user experience by showing skeleton loaders instead of stale data while waiting for API confirmation. ### What is the reason for the change? Previously, when users placed orders in the Predict feature, they had to wait for the API to confirm the transaction before seeing their position update. This created a poor UX where: 1. Users saw outdated position values after placing orders 2. No visual feedback indicated that an order was processing 3. Users were unsure if their action succeeded until API confirmed ### What is the improvement/solution? **Implemented a comprehensive optimistic updates system:** #### Core Features - **Optimistic position creation**: When users BUY, create an immediate optimistic position with expected values - **Optimistic position updates**: When users BUY more of an existing position, optimistically update with accumulated values - **Optimistic position removal**: When users SELL or CLAIM, immediately hide the position from the list - **Smart validation**: Compare API responses with expected sizes to know when to remove optimistic updates - **Auto-cleanup**: Remove optimistic updates after 1-minute timeout if API never confirms - **Defensive checks**: Prevent optimistic updates on claimable positions #### Implementation Details 1. **PolymarketProvider.ts** (~450 lines added): - Added `OptimisticUpdateType` enum (CREATE, UPDATE, REMOVE) - Added `OptimisticPositionUpdate` interface with type, position data, and expected size - Added `#optimisticPositionUpdatesByAddress` Map to track updates per user address - Implemented `createOrUpdateOptimisticPosition()` for BUY orders - Implemented `removeOptimisticPosition()` for SELL/CLAIM orders - Implemented `applyOptimisticPositionUpdates()` to merge optimistic data with API responses - Implemented `isApiPositionUpdated()` with 0.1% tolerance for size validation - Added cleanup logic for expired optimistic updates (1-minute timeout) 2. **UI Components**: - **PredictPosition.tsx**: Added skeleton loaders for current value and PnL when `optimistic: true` - **PredictPositionDetail.tsx**: Added skeleton loaders and disabled "Cash out" button for optimistic positions - **PredictPosition types**: Added `optimistic?: boolean` flag to `PredictPosition` type 3. **Controller**: - **PredictController.ts**: Include fees in optimistic balance calculation for accurate display 4. **Comprehensive Test Coverage** (~1,830 lines of tests): - Fixed 8 failing tests from system migration - Added 21 new tests covering CREATE, UPDATE, REMOVE, integration, and UI scenarios - Achieved 91.53% statement coverage and 91.75% line coverage ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [PRED-294](https://consensyssoftware.atlassian.net/browse/PRED-294) ## **Manual testing steps** ```gherkin Feature: Optimistic updates for Predict positions Scenario: User buys a new position Given user is on the Predict Positions screen And user has no position in a market When user places a BUY order for a position Then user immediately sees the new position in their list And the position shows skeleton loaders for value and PnL And the initial value and shares are displayed When the API confirms the order (within 1 minute) Then the skeleton loaders are replaced with actual values And the position shows real-time current value and PnL Scenario: User sells an existing position Given user is on the Predict Positions screen And user has an existing position When user places a SELL order for the position Then the position immediately disappears from the list When the API confirms the sale Then the position remains hidden (optimistic update removed) Scenario: User buys more of an existing position Given user has an existing position with 10 shares When user places another BUY order for the same position Then the position shows skeleton loaders And the expected accumulated values are displayed When the API confirms the order Then actual updated values replace the skeletons Scenario: API timeout cleanup Given user placed a BUY order 1 minute ago And the API has not yet confirmed When 1 minute has passed since the order Then the optimistic update is automatically cleaned up And user sees either the confirmed API position or no position ``` ## **Screenshots/Recordings** ### **Before** After placing an order, users saw stale position data with no indication that an order was processing. ### **After** After placing an order, users immediately see: - New positions appear with skeleton loaders - Existing positions update with skeleton loaders - Sold positions disappear immediately - Skeleton loaders are replaced with real values when API confirms https://github.com/user-attachments/assets/a2b08c94-f223-41a0-b85f-615abd800780 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- ## **Technical Implementation Summary** ### Files Changed - `PolymarketProvider.ts`: +450 lines (optimistic update system) - `PredictPosition.tsx`: +29 lines (skeleton loaders) - `PredictPositionDetail.tsx`: +27 lines (skeleton loaders, disabled button) - `PredictController.ts`: +3 lines (fee calculation) - `types/index.ts`: +1 line (`optimistic?: boolean` flag) - Test files: +1,830 lines (comprehensive coverage) ### Optimistic Update Flow **BUY Order:** 1. User places BUY order → `placeOrder()` called 2. Order submitted to API via `submitClobOrder()` 3. On success, `createOrUpdateOptimisticPosition()` called 4. Optimistic position created with `optimistic: true` flag 5. `getPositions()` merges optimistic position with API data 6. UI shows skeleton loaders for value/PnL 7. When API returns position with expected size → optimistic update removed 8. If API doesn't confirm within 1 minute → optimistic update expires **SELL/CLAIM Order:** 1. User places SELL/CLAIM order → `placeOrder()` or `confirmClaim()` called 2. `removeOptimisticPosition()` marks position for removal 3. `getPositions()` filters out the position 4. Position immediately disappears from UI 5. When API confirms (position gone or size reduced) → optimistic update removed ### Test Coverage **Total: 21 new tests added** **PolymarketProvider (14 tests):** - CREATE scenarios: 7 tests (position creation, value calculation, market details) - UPDATE scenarios: 4 tests (accumulation, avgPrice, preservation) - Integration: 3 tests (BUY→confirm, timeout, BUY→SELL) **UI Components (7 tests):** - PredictPosition: 4 tests (skeleton display, value hiding) - PredictPositionDetail: 3 tests (skeleton display, button state) **Coverage Achieved:** - Statements: 91.53% ✅ - Branches: 83.01% ✅ - Functions: 91.6% ✅ - Lines: 91.75% ✅ All metrics exceed the 80% target. [PRED-294]: https://consensyssoftware.atlassian.net/browse/PRED-294?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds full optimistic position create/update/remove flow with UI skeletons, disables actions during optimism, adjusts balance for fees, and expands tests. > > - **Predict Provider (Polymarket)**: > - Implement optimistic updates system (`CREATE`/`UPDATE`/`REMOVE`) via in-memory map keyed by address and `outcomeTokenId`. > - Merge optimistic state in `getPositions` with timeout cleanup (1 min) and API-size validation tolerance. > - Block orders on claimable positions; add targeted fetch by `outcomeId` in `getPositions`. > - Apply optimistic removal on SELL and CLAIM; create/update optimistic positions on BUY using market details when available. > - **UI**: > - `PredictPosition` and `PredictPositionDetail`: show skeletons for value/PnL when `position.optimistic` is true; disable "Cash out" for optimistic positions. > - **Controller**: > - Deduct total fees from balance during optimistic BUY balance update. > - **Types/Providers API**: > - Add `optimistic?: boolean` to `PredictPosition`; add `outcomeId` to `GetPositionsParams` and wire through provider method. > - **Tests**: > - Extensive new tests covering optimistic create/update/remove flows, integration scenarios, and UI behavior. > - **Misc**: > - Minor hook lint suppression in `usePredictPrices`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 144511a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** This PR reverts commit 74b8745 from PR #21199. **What is the reason for the change?** The font preloader changes introduced in #21199 are causing rendering bugs in the application: - Text is being cut off in various components - Font weights are not loading correctly - The comprehensive font preloading approach is causing unexpected layout issues **What is the improvement/solution?** This revert restores the previous variant-based font preloading approach, which: - Preloads only the specific TextVariant fonts that are actively used - Maintains stable font rendering without text cutoff issues - Ensures font weights load properly across all components - Restores the working implementation until the font loading issues can be properly addressed ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: #22301 Reverts: #21199 Original commit: 74b8745 ## **Manual testing steps** ```gherkin Feature: Font rendering after revert Scenario: user views text content across the app Given the user has the app running with the reverted font preloader And the user navigates through different screens with various text components When the user views text content in input fields, headings, and body text Then all text should be fully visible without cutoff And font weights should render correctly (regular, medium, bold) And there should be no layout shifting or text overflow issues ``` ## **Screenshots/Recordings** ### **Before** N/A - This is a revert PR ### **After** N/A - This is a revert PR ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Reverts/rewrites font preloader to load only TextVariant fonts and updates input styles to set fontWeight from theme while removing hardcoded lineHeight/fontFamily; updates tests and snapshots accordingly. > > - **Fonts**: > - **Preloader** (`app/core/FontPreloader/FontPreloader.ts`): revert to variant-based font loading using `TextVariant` and `getFontFamily`; preload 400/500/700 weights on web; streamline native preload and logging. > - **Tests** (`app/core/FontPreloader/__tests__/FontPreloader.test.ts`): simplify and align with new preloader behavior (singleton, RN preload, concurrency, reset, errors, promise access). > - **UI Styles**: > - **Inputs** (`app/component-library/.../Input.styles.ts`): apply `fontWeight` from `theme.typography[textVariant]`; keep baseline alignment; minor comment/format tweak. > - Remove hardcoded `fontFamily` in custom inputs (`Views/EnterPasswordSimple/index.js`, `Views/RevealPrivateCredential/styles.ts`, `Views/MultichainAccounts/PrivateKeyList/styles.ts`). > - **Snapshots**: update across UI to reflect `fontWeight: "400"` and removal of explicit `lineHeight`/`fontFamily` where applicable. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 09ccad9. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
This PR implements automatic eligibility refresh for the Predict feature
when the app comes to foreground. Previously, eligibility was only
checked on initial load or manual refresh. Now, when a user backgrounds
the app and then returns to it, the eligibility status is automatically
refreshed.
**What is the reason for the change?**
Users may change their network configuration (e.g., switching between
different network connections) while the app is backgrounded. When they
return to the app, the Predict feature should automatically check
eligibility again to reflect any potential changes in their connection
status.
**What is the improvement/solution?**
- Added an `AppState` listener to the `usePredictEligibility` hook that
detects when the app transitions from `background`/`inactive` to
`active` state
- Implemented 1-minute debouncing to prevent excessive API calls if the
user switches in and out of the app multiple times
- Manual refresh functionality remains unchanged and bypasses the
debounce
- Added comprehensive error handling and logging
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: Auto-refresh Predict eligibility on app focus
Scenario: user returns to app and eligibility is refreshed
Given user has opened the Predict feature
And user is eligible to use Predict
When user backgrounds the app (switches to another app)
And user returns to the app
Then eligibility is automatically refreshed
And user sees updated eligibility status if it changed
Scenario: user rapidly switches in and out of app
Given user has opened the Predict feature
And eligibility was just refreshed
When user backgrounds the app
And user returns to the app within 1 minute
Then eligibility refresh is skipped due to debouncing
And user still has access to Predict feature
Scenario: user returns after debounce period
Given user has opened the Predict feature
And eligibility was refreshed more than 1 minute ago
When user backgrounds the app
And user returns to the app
Then eligibility is automatically refreshed
```
## **Screenshots/Recordings**
N/A - This is an internal behavior change with no visual UI impact.
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Introduce a singleton-managed AppState listener to auto-refresh
Predict eligibility on app foreground with 1-minute debounce, logging,
and race-condition prevention, plus comprehensive tests.
>
> - **Predict Hook (`usePredictEligibility.ts`)**:
> - **Singleton manager (`EligibilityRefreshManager`)**:
> - Manages a single `AppState` `change` listener across hook instances.
> - Refreshes `Engine.context.PredictController.refreshEligibility()` on
transition to `active`.
> - Debounces auto-refreshes by 60s; manual `refreshEligibility`
bypasses debounce.
> - Prevents concurrent calls by reusing in-flight promise; tracks last
refresh time.
> - Registers/unregisters per hook mount/unmount; adds detailed
`DevLogger` logs and error handling.
> - **Tests (`usePredictEligibility.test.ts`)**:
> - Cover eligibility state selection, singleton
registration/unregistration, app focus auto-refresh, debounce behavior,
manual refresh bypass, error logging/continuation, and
concurrency/race-condition scenarios.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8c94340. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**
This PR migrates the Predict feature flag from a simple boolean flag to
a version-gated feature flag structure, aligning it with the pattern
used by Perps and other features.
**What is the reason for the change?**
The Predict feature needs version gating to ensure users have the
minimum required app version (7.60.0) before accessing the feature. The
previous implementation used a simple boolean flag (`predictEnabled`)
which didn't support version checking.
**What is the improvement/solution?**
- Changed flag name from `predictEnabled` to `predictTradingEnabled` to
follow naming conventions
- Implemented version-gated structure with `enabled` and
`minimumVersion` properties
- Added environment variable fallback (`MM_PREDICT_ENABLED`) for local
development
- Updated all references across the codebase (selectors, tests, mocks,
E2E helpers)
- Ensured backward compatibility by maintaining the same boolean return
type
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Predict feature flag version gating
Scenario: user with app version below minimum cannot access Predict
Given user has app version 7.59.0
And remote feature flag predictTradingEnabled is enabled with minimumVersion "7.60.0"
When user navigates to Wallet screen
Then Predict feature should not be visible/accessible
Scenario: user with app version at or above minimum can access Predict
Given user has app version 7.60.0 or higher
And remote feature flag predictTradingEnabled is enabled with minimumVersion "7.60.0"
When user navigates to Wallet screen
Then Predict feature should be visible and accessible
Scenario: local environment variable overrides when remote flag unavailable
Given remote feature flags are empty or invalid
And MM_PREDICT_ENABLED environment variable is set to "true"
When app initializes
Then Predict feature should be enabled based on local flag
Scenario: remote flag takes precedence over local flag
Given remote feature flag predictTradingEnabled is explicitly disabled
And MM_PREDICT_ENABLED environment variable is set to "true"
When app initializes
Then Predict feature should be disabled (remote flag overrides local)
```
## **Screenshots/Recordings**
Not applicable - This is an internal refactoring with no UI changes.
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
---
## **Technical Details**
### Files Modified (7 total)
1. **`app/components/UI/Predict/selectors/featureFlags/index.ts`**
- Migrated from boolean flag to `VersionGatedFeatureFlag` structure
- Changed flag name: `predictEnabled` → `predictTradingEnabled`
- Added environment variable fallback: `MM_PREDICT_ENABLED`
- Added comprehensive JSDoc documentation
2. **`app/components/UI/Predict/selectors/featureFlags/index.test.ts`**
- Rewrote tests following unit testing guidelines (AAA pattern)
- Added comprehensive test coverage for version gating
- Added tests for remote flag precedence over local flags
- Added tests for invalid flag scenarios
- All 19 tests passing ✅
3. **`app/components/UI/Predict/mocks/remoteFeatureFlagMocks.ts`**
- Updated mock structure to version-gated format
4. **`app/components/Views/Wallet/index.test.tsx`**
- Updated 5 occurrences of `predictEnabled` → `predictTradingEnabled`
5. **`.js.env.example`**
- Added `MM_PREDICT_ENABLED` environment variable example
6. **`e2e/api-mocking/helpers/remoteFeatureFlagsHelper.ts`**
- Updated default mock to version-gated structure
7. **`e2e/api-mocking/mock-responses/feature-flags-mocks.ts`**
- Updated `remoteFeatureFlagPredictEnabled` function
### Key Implementation Details
- **Flag Structure**: `{ enabled: boolean, minimumVersion: string }`
- **Backend Flag Name**: `predictTradingEnabled`
- **Minimum Version**: `7.60.0`
- **Local Fallback**: `MM_PREDICT_ENABLED` environment variable
(defaults to `false`)
- **Validation**: Uses `validatedVersionGatedFeatureFlag()` utility for
type checking and version validation
### Test Coverage
- ✅ Remote flag precedence over local flags
- ✅ Version gating validation
- ✅ Invalid flag type handling
- ✅ Fallback to local environment variable
- ✅ Edge cases (null, undefined, empty objects)
### Breaking Changes
None - The selector maintains the same boolean return type, ensuring
backward compatibility with existing code.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Migrates Predict flag to version-gated `predictTradingEnabled` (with
minimumVersion and `MM_PREDICT_ENABLED` fallback) and updates selectors,
tests, and mocks accordingly.
>
> - **Predict feature flag**:
> - Rename `predictEnabled` → `predictTradingEnabled`.
> - Adopt version-gated structure `{ enabled, minimumVersion }` (min app
`7.60.0`).
> - Update selector to validate remote flag and fallback to
`MM_PREDICT_ENABLED`.
> - **Tests**:
> - Add/expand unit tests for precedence, version gating, and invalid
scenarios in `selectors/featureFlags`.
> - Update `Wallet` tests to use `predictTradingEnabled` objects.
> - **Mocks/E2E**:
> - Update Predict mocks and remote flags helpers to new structure.
> - Add `MM_PREDICT_ENABLED` to `.js.env.example`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8997c9e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#22499) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Changes the auto-refresh behavior in usePredictOrderPreview from interval-based to sequential pattern. The timer now waits for the preview response before starting the timeout countdown, preventing overlapping requests. Key changes: - Replace setInterval with recursive setTimeout pattern - Add scheduleNextRefresh function to trigger after response - Schedule next refresh after both successful and error responses - Clear pending timers on unmount and parameter changes - Update tests to verify sequential refresh behavior This ensures the autoRefreshTimeout is a delay AFTER each response completes, rather than a fixed interval that could cause overlapping requests when API response times exceed the timeout value. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: [PRED-299](https://consensyssoftware.atlassian.net/browse/PRED-299?atlOrigin=eyJpIjoiOTQwNThkMTg4N2UzNDQ1MjljZTEyNGM0MTlhOGZjMjUiLCJwIjoiaiJ9) ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces interval-based auto-refresh with response-triggered sequential timeouts in `usePredictOrderPreview`, adds cleanup on param changes/unmount, and updates tests accordingly. > > - **Hook `usePredictOrderPreview`**: > - Replace `setInterval` auto-refresh with sequential `setTimeout` scheduled via `scheduleNextRefresh` after each response (success or error). > - Introduce refs for timer and callbacks: `refreshTimerRef`, `calculatePreviewRef`, `scheduleNextRefreshRef`. > - Clear pending refresh timers on unmount and when parameters change; debounce initial calculation. > - Minor safety: optional chaining on `calculatePreviewRef.current?.()`. > - **Tests `usePredictOrderPreview.test.ts`**: > - Rename and add cases to verify response-triggered scheduling, waiting before countdown, scheduling after errors, and clearing timers on parameter changes and unmount. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2c9fb28. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [PRED-299]: https://consensyssoftware.atlassian.net/browse/PRED-299?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
This PR bumps the network-enablement-controller to version 3.1.0 that
includes monad in the constant.
This allows monad to be selected when clicking on the `All popular
networks` button in the Networks Modal.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: bumps network-enablement-controller and apply patch
similar to patch on 3.0.0
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
<img width="384" height="792" alt="Screenshot 2025-11-11 at 17 01 05"
src="https://github.com/user-attachments/assets/0726e0c3-eb8a-4817-9e4a-f101a664274b"
/>
### **After**
<!-- [screenshots/recordings] -->
<img width="384" height="792" alt="Screenshot 2025-11-11 at 17 11 43"
src="https://github.com/user-attachments/assets/83bc4ca7-adf1-42ef-be11-3db8842deef0"
/>
## **Pre-merge author checklist**
- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Updates @metamask/network-enablement-controller to 3.1.0 with a patch
that enables additional EVM networks by default.
>
> - **Dependencies**:
> - Bump `@metamask/network-enablement-controller` from `3.0.0` to
`3.1.0` using a Yarn patch.
> - **Network defaults** (`dist/NetworkEnablementController.cjs`):
> - Extend default-enabled EVM networks by adding `ArbitrumOne`,
`BscMainnet`, `OptimismMainnet`, `PolygonMainnet`, and `SeiMainnet`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b41bb09. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…21990) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> When Redux state migrations fail, redux-persist resets the state to defaults and updates the version number to the latest, preventing migrations from re-running. This leaves users stuck on the onboarding screen unable to access their wallets, even though their vault backup exists in secure storage. ## Implementation ### 1. Vault Recovery Detection on Onboarding Screen Added automatic detection when users land on the onboarding screen with an existing vault backup: - Detects migration failure scenario: `!existingUser` (Redux reset) + vault backup exists - Skips detection if user explicitly deleted their wallet (`route.params.delete`) - Automatically navigates to vault recovery screen - Users can restore their wallet using their password - Prevents data loss from failed migrations **Files Changed:** - `app/components/Views/Onboarding/index.js` - Added vault recovery detection - `app/components/Views/RestoreWallet/WalletRestored.tsx` - Sets `existingUser` flag after restore ### 2. Fixed Vault Recovery Persistence Bug Fixed critical bug where vault recovery didn't persist controller state changes: - Added `setupEnginePersistence()` call in `initializeVaultFromBackup()` path - Ensures controller state changes are saved to individual files after vault recovery - Previously caused infinite vault recovery loops after successful restore - Consolidated persistence setup in `initializeControllers()` for consistency **Files Changed:** - `app/core/EngineService/EngineService.ts` - Fixed persistence setup in vault recovery path ### 3. Fixed Race Condition in Wallet Deletion Prevents temporary wallets (created during reset) from being backed up: - Added `disableAutomaticVaultBackup` flag to temporarily disable vault backups during wallet reset - Clears all vault backups before creating temporary wallet - Re-enables automatic backups in `finally` block for robustness - Applies to both manual wallet deletion and OAuth error recovery - Prevents false vault recovery prompts after intentional wallet resets **Files Changed:** - `app/core/Engine/Engine.ts` - Added circuit breaker flag - `app/components/hooks/DeleteWallet/useDeleteWallet.ts` - Manual deletion fix - `app/core/Authentication/Authentication.ts` - Uncommented `setExistingUser(true)` for new wallets - `app/core/BackupVault/backupVault.ts` - Vault backup utilities ### 4. Fixed Migration Inflation/Deflation Logic Corrected conditions for the new file-based persistence system (migrations 104-105): - **Inflation**: `> 106` - Only migrations 106+ need to inflate from individual controller files - **Deflation**: `>= 106` - Migration 106 is the first to deflate into individual controller files - Only future migrations require inflation, that will follow this PR - Ensures smooth transition to new persistence system without breaking app on restart **Files Changed:** - `app/store/migrations/index.ts` - Fixed inflation/deflation conditions and removed debug logs - `app/store/migrations/index.test.ts` - Updated tests to reflect correct logic ### 5. Code Cleanup Removed all debugging logs added during investigation: - `app/components/Views/Onboarding/index.js` - Removed migration detection logs - `app/core/EngineService/EngineService.ts` - Removed persistence setup logs - `app/store/migrations/index.ts` - Removed KeyringController debug logs - `app/core/BackupVault/backupVault.ts` - Simplified error handling - `app/core/Engine/Engine.ts` - Removed vault backup logs ### 6. Test Compliance Fixed unit test naming violations to comply with project guidelines: - Updated 19 tests in `EngineService.test.ts` to remove "should" from test names - Ensured all tests follow action-oriented naming convention ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` **Feature: Vault Recovery After Migration Failure** Scenario: user restores wallet after migration failure Given user has MetaMask installed with wallet data And a state migration fails during app startup And redux state is reset to defaults And vault backup exists in secure storage When user opens the app Then user sees the vault recovery screen automatically When user enters their wallet password Then user successfully restores their wallet And user can access their accounts and assets **Feature: Manual Wallet Deletion** Scenario: user deletes wallet without false vault recovery Given user has MetaMask installed with an active wallet And user is on the Settings screen When user navigates to "Security & Privacy" And user taps "Delete Wallet" And user confirms the deletion And user restarts the app Then user sees the onboarding screen And user does NOT see the vault recovery screen **Feature: OAuth Login Error Recovery** Feature: Vault Recovery After Migration Failure Scenario: user restores wallet after migration failure Given user has MetaMask installed with wallet data And a state migration fails during app startup And redux state is reset to defaults And vault backup exists in secure storage When user opens the app Then user sees the vault recovery screen automatically When user enters their wallet password Then user successfully restores their wallet And user can access their accounts and assets **Feature: Manual Wallet Deletion** Scenario: user deletes wallet without false vault recovery Given user has MetaMask installed with an active wallet And user is on the Settings screen When user navigates to "Security & Privacy" And user taps "Delete Wallet" And user confirms the deletion And user restarts the app Then user sees the onboarding screen And user does NOT see the vault recovery screen **Feature: OAuth Login Error Recovery** Scenario: user experiences OAuth backup failure without false vault recovery Given user is creating a new wallet with OAuth (Google/Apple login) And local wallet creation succeeds And cloud backup fails during OAuth process When the error handler resets the wallet state And user restarts the app Then user sees the onboarding screen And user does NOT see the vault recovery screen And user can retry OAuth login or import with seed phrase **Feature: Migration System Upgrade Path** Scenario: user upgrades from version 103 to version 104+ Given user has MetaMask version with migrations up to 103 And controller data is stored in redux-persist And user has an active wallet When user upgrades to version 104 or higher Then migrations 104+ run successfully And controller data is deflated to individual files And user's wallet remains accessible And app functions normally after restart Scenario: user upgrades from version 104 to version 105+ Given user has MetaMask version 104 And controller data is in individual files And user has an active wallet When user upgrades to version 105 or higher Then controller data is inflated for migrations And new migrations run successfully And controller data is deflated back to individual files And user's wallet remains accessible And app functions normally after restart**: user experiences OAuth backup failure without false vault recovery Given user is creating a new wallet with OAuth (Google/Apple login) And local wallet creation succeeds And cloud backup fails during OAuth process When the error handler resets the wallet state And user restarts the app Then user sees the onboarding screen And user does NOT see the vault recovery screen And user can retry OAuth login or import with seed phrase **Feature: Migration System Upgrade Path** Scenario: user upgrades from version 103 to version 104+ Given user has MetaMask version with migrations up to 103 And controller data is stored in redux-persist And user has an active wallet When user upgrades to version 104 or higher Then migrations 104+ run successfully And controller data is deflated to individual files And user's wallet remains accessible And app functions normally after restart Scenario: user upgrades from version 104 to version 105+ Given user has MetaMask version 104 And controller data is in individual files And user has an active wallet When user upgrades to version 105 or higher Then controller data is inflated for migrations And new migrations run successfully And controller data is deflated back to individual files And user's wallet remains accessible And app functions normally after restart ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Detects migration failure and routes to vault recovery, ensures controller persistence after recovery, prevents backing up temporary wallets during resets, and updates login/recovery flows with tests. > > - **Onboarding/Recovery**: > - Detects migration failure on `Onboarding` by checking vault backup and `existingUser`; skips in E2E and explicit delete, then navigates to `Routes.VAULT_RECOVERY.RESTORE_WALLET`. > - `WalletRestored` now routes to `Routes.ONBOARDING.LOGIN` with `isVaultRecovery` instead of auto-auth; adds tests. > - `Login` sets `existingUser` via `setExistingUser(true)` after successful unlock when `isVaultRecovery` is true; adds tests. > - **Engine/Authentication**: > - Adds `Engine.disableAutomaticVaultBackup` and skips `backupVault` when true. > - Clears vault backups and temporarily disables auto-backup during wallet reset and OAuth error recovery; always re-enables. > - `EngineService` moves filesystem persistence setup to `initializeControllers` and ensures it runs after vault recovery; updates batching and tests. > - **Hooks/Tests**: > - `useDeleteWallet` clears backups first, disables auto-backup during reset, re-enables in `finally`, and resets controllers; adds robust tests. > - Renames and tightens numerous test titles/expectations; snapshot names updated. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ed1a8a7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR adds analytics tracking for social login failures to help identify where and why failures occur during the OAuth login flow. The implementation tracks failures at three stages: 1. **Provider login failures** - When users cancel or encounter errors during the OAuth provider authentication step 2. **Token exchange failures** - When errors occur during the authorization code to JWT token exchange 3. **Seedless authentication failures** - When errors occur during the seedless authentication step Each failure event includes contextual metadata: - `account_type` - The type of account being created (e.g., `default_google`, `default_apple`) - `is_rehydration` - Whether this is a rehydration flow (existing user returning) - `failure_type` - Whether the failure was due to user cancellation or an error - `error_category` - The specific stage where the failure occurred ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/SL-257 ## **Manual testing steps** 1. Start a social login flow (Google or Apple) 2. Cancel the OAuth provider authentication dialog 3. Verify that a `SocialLoginFailed` event is tracked with `failure_type: 'user_cancelled'` and `error_category: 'provider_login'` 4. Attempt a social login and simulate a network error during token exchange 5. Verify that a `SocialLoginFailed` event is tracked with `failure_type: 'error'` and `error_category: 'get_auth_tokens'` 6. Attempt a social login and simulate an error during seedless authentication 7. Verify that a `SocialLoginFailed` event is tracked with `failure_type: 'error'` and `error_category: 'seedless_auth'` ## **Screenshots/Recordings** <!-- Not applicable - this is an analytics-only change with no UI changes --> ### **Before** <!-- N/A --> ### **After** <!-- N/A --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds SOCIAL_LOGIN_FAILED tracking with rehydration context across provider login, token exchange, and seedless auth; updates OAuth login API and tests accordingly. > > - **Analytics**: > - Add `SOCIAL_LOGIN_FAILED` event in `core/Analytics/MetaMetrics.events.ts` and export mapping. > - **OAuth** (`core/OAuthService/OAuthService.ts`): > - Add `userClickedRehydration` to local state and `#trackSocialLoginFailure` to emit `SOCIAL_LOGIN_FAILED` with `account_type`, `is_rehydration`, `failure_type`, and `error_category`. > - Invoke tracking on failures in `provider_login`, `get_auth_tokens`, and `seedless_auth` stages; validate `id_token` earlier. > - Change `handleOAuthLogin(loginHandler, userClickedRehydration)` signature and wire usage. > - **Onboarding** (`components/Views/Onboarding/index.js`): > - Pass rehydration flag to `handleOAuthLogin` (`!createWallet`). > - **Tests**: > - Update unit tests in `OAuthService.test.ts` and `Onboarding/index.test.tsx` to reflect new `handleOAuthLogin` param and event behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 37e8b08. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR fixes styling for "unconfirmed" transaction status <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed styling for "unconfirmed" transaction status ## **Related issues** Fixes: #21574 https://consensyssoftware.atlassian.net/browse/TMCU-158 ## **Manual testing steps** ```gherkin Feature: Send BTC Scenario: user sends BTC Given BTC is enabled When user initiates BTC transaction and navigates to Activity tab Then unconfirmed transaction with yellow/orange "Pending" status should appear ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="395" height="835" alt="Screenshot 2025-11-07 at 13 53 14" src="https://github.com/user-attachments/assets/e74b1b50-be28-4800-a1cc-6be00665d119" /> <!-- [screenshots/recordings] --> ### **After** <img width="396" height="833" alt="Screenshot 2025-11-07 at 13 52 51" src="https://github.com/user-attachments/assets/431a522f-0338-4b22-b39a-29d51d03dfca" /> <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Maps `Unconfirmed` statuses to pending and enables overriding styles on status text components; updates i18n and snapshots. > > - **UI**: > - `app/components/Base/StatusText.js`: > - `ConfirmedText`, `PendingText`, `FailedText` now accept optional `style` prop merged with base styles. > - Treat `"Unconfirmed"/"unconfirmed"` as pending in `StatusText` switch. > - **i18n**: > - `locales/languages/en.json`: add `"transaction.unconfirmed": "Pending"`. > - **Tests**: > - Update `TransactionDetails` snapshots to reflect array-based `style` merging. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fa44247. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
PR to add trending tokens card. This should be under a feature flag(
selector `selectAssetsTrendingTokensEnabled`)
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: No functional changes, this is still under a feature
flag.
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
<img width="425" height="858" alt="Screenshot 2025-11-11 at 18 09 58"
src="https://github.com/user-attachments/assets/ff394cf2-fbc8-4965-a2d1-e048eb1990ad"
/>
## **Pre-merge author checklist**
- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Introduces a Trending Tokens UI section integrated into TrendingView
with a shared token logo hook, updates the trending fetch hook to
default to popular networks, and adds comprehensive tests and i18n.
>
> - **UI (Trending)**:
> - **Trending Tokens Section**: New `TrendingTokensSection` with
`TrendingTokensList`, `TrendingTokenRowItem`, `TrendingTokenLogo`, and
`TrendingTokensSkeleton`, integrated into `TrendingView` (header tweak,
scroll container).
> - **Hooks**:
> - **New**: `useTokenLogo` for shared image loading/error/background
logic; refactors `PerpsTokenLogo` to use it.
> - **Updated**: `useTrendingRequest` now accepts optional `chainIds`,
defaults to popular networks via
`useNetworksByNamespace`/`useNetworksToUse`, sets initial loading to
true, and fixes debounce dependencies.
> - **Utils**:
> - Add formatting helpers `formatCompactUSD` and `formatMarketStats`
for market cap/volume.
> - **Tests**:
> - Add extensive unit tests and snapshots for new components/hooks and
updated trending request behavior.
> - **Localization**:
> - Update `en.json` with `trending.title`, `trending.view_all`, and
`trending.tokens` strings.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
49ddd1a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description** Ensure the Predict withdraw confirmation uses the entire balance if the `Max` button is used. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [#6156](MetaMask/MetaMask-planning#6156) #22190 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Ensure Predict withdraw Max uses the full balance converted to USD and add a fixed 1:1 USD rate for Polygon USDCE. > > - **Confirmations / Amounts**: > - Convert Predict balance to USD via `tokenFiatRate` for withdraw calculations and `Max` behavior; default rate falls back to `1`. > - Refine max-percentage logic when pay token is missing or matches the first required token. > - **Token Fiat Rates**: > - Return fixed `1` rate for `POLYGON_USDCE` on `POLYGON` when currency is USD (alongside `ARBITRUM_USDC`). > - Minor refactor for USD checks and token matches. > - **Alerts**: > - Use human Predict balance in `useInsufficientPredictBalanceAlert` comparison. > - **Tests**: > - Update and add tests for USDCE fixed rate and Predict withdraw USD conversion/max behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f179f68. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adjusted the funding tooltip copy in the position component to display position-specific information. Previously, both the position card's "Funding Cost" and the market statistics "Funding Rate" used the same generic tooltip explaining funding rates. This change adds a dedicated tooltip for funding payments that clarifies it represents the cumulative amount paid/received since the position opened. **Changes:** - Added new `funding_payments` tooltip type - Updated position card to use the new tooltip - Market statistics continues to use the existing `funding_rate` tooltip ## **Changelog** CHANGELOG entry: Updated funding tooltip in position component to show position-specific information ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TAT-1880 ## **Manual testing steps** ```gherkin Feature: Funding payments tooltip in position component Scenario: user views funding tooltip in position card Given user has an open perp position And the position card displays the "Funding" field with an info icon When user taps the info icon next to "Funding" in the position card Then the tooltip displays title "Funding payments" And the tooltip content reads "This is the amount you've paid in funding fees since the position was opened. Funding is paid or received every hour to keep the perp price close to the actual token price." Scenario: user views funding rate tooltip in market statistics Given user is viewing market statistics for a perp When user taps the info icon next to "Funding rate" Then the tooltip displays title "Funding rate" And the tooltip content describes the general funding rate concept ``` ## **Screenshots/Recordings** ### **Before** Position card showed generic funding rate tooltip (same as market statistics) ### **After** Position card shows position-specific funding payments tooltip with cumulative payment context https://github.com/user-attachments/assets/65db42a1-68fc-4758-950f-ad1dd79e1030 ## **Pre-merge author checklist** - [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding Standards - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable (N/A - localization change only) - [x] I've documented my code using JSDoc format if applicable (N/A) - [x] I've applied the right labels on the PR ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed) - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces a new `funding_payments` tooltip and switches the position card’s funding info icon to use it, with corresponding registry and locale updates. > > - **Perps Tooltips**: > - Add new content key `funding_payments` to `PerpsTooltipContentKey` and register in `contentRegistry`. > - **Position Card**: > - Change funding info icon handler from `funding_rate` to `funding_payments` in `PerpsPositionCard`. > - **Localization**: > - Add `perps.tooltips.funding_payments` strings (title and content) in `en.json`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2149df2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR enables back native token send. As it stated in the previous automated flaky test thread [here](https://consensys.slack.com/archives/C02U025CVU4/p1762243312142959) and the [logs](https://github.com/MetaMask/metamask-mobile/actions/runs/19055429448/job/54425009493), send native spec was failing. However if you look at the logs - this is not entirely related as there is a detox crash. I ran these tests over and over on local but I couldn't encoutner the issue once, hence we are enabling it back. https://github.com/user-attachments/assets/042fdb4f-c846-4e7c-92d9-6985798e3de0 **Update 1** We still encounter the issues in the CI - Ola [had a look but no chance](https://consensys.slack.com/archives/C01U65ZUS2E/p1762787121323169?thread_ts=1762776032.589089&cid=C01U65ZUS2E). Hence we are disabling this `50%` test rest looks good. **Update 2** It appears the issues are because of `%` text. I changed e2e test to lookup component test ids instead of text and it worked. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: #22135 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [X] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I’ve included tests if applicable - [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds testIDs to percentage buttons and updates send flow e2e selectors to target them by ID. > > - **UI**: > - Add `testID` to percentage buttons in `app/components/Views/confirmations/components/edit-amount-keyboard/edit-amount-keyboard.tsx` as `percentage-button-<value>`. > - **E2E Tests**: > - Update `e2e/pages/Send/RedesignedSendView.ts` to select `50%` and `Max` via `getElementByID('percentage-button-50'|'percentage-button-100')` instead of text. > - Keep send native token spec logic the same while interacting with the new IDs. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 505718b. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…tion cp-7.59.0 (#22252) ## **Description** This PR implements a major refactor of the Perps order handling system to address precision and validation issues. The changes establish USD as the primary source of truth for order amounts, replacing the complex `findOptimalAmount` optimization logic with a simpler, more robust approach that recalculates position sizes at execution time using fresh market prices. ### Key Changes #### 1. Migration from `findOptimalAmount` to USD-as-Source-of-Truth **Previous Approach:** - Used `findOptimalAmount` function to find the "optimal" USD amount that maximized value while maintaining the same position size - Performed complex calculations with position size increments and rounding - Optimized order amounts on every input change (percentage, slider, keypad, etc.) - Position size was calculated once in the UI and used directly for order placement **New Approach:** - **USD amount is now the primary source of truth** - stored and validated as entered by user - Position size is recalculated at execution time with the freshest available price - Eliminates complex optimization logic (~150 lines removed from `orderCalculations.ts`) - Simplified order form handling (~71 lines removed from `usePerpsOrderForm.ts`) **Benefits:** - Eliminates edge cases where optimization could produce invalid orders - Reduces computational overhead on every input change - More predictable behavior - what user enters is what gets validated and executed - Better handling of price volatility during order placement #### 2. Standardized Slippage Management **New Configuration:** ```typescript export const ORDER_SLIPPAGE_CONFIG = { DEFAULT_SLIPPAGE_BPS: 100, // 100 basis points = 1% } as const; ``` **Improvements:** - Unified slippage configuration using basis points for consistency - Added price staleness validation to prevent execution with stale prices - New `priceAtCalculation` and `maxSlippageBps` fields in `OrderParams` - Provider validates price hasn't moved beyond tolerance before execution - Standardized slippage across market orders, position closing, and TP/SL orders **Slippage Validation Example:** ```typescript // Provider checks price delta before order execution const priceDeltaBps = Math.abs( ((currentPrice - priceAtCalculation) / priceAtCalculation) * 10000 ); if (priceDeltaBps > maxSlippageBps) { throw new Error(`Price moved too much: ${priceDeltaBps} bps`); } ``` #### 3. Enhanced Order Validation **Validation Improvements:** - **USD as source of truth for minimum validation** - validates user's exact USD input without recalculation - Example: User enters $10 → validates $10 directly (no rounding errors) - For full position closes (e.g., Close All), minimum validation is skipped - Added `skipValidation` flag to prevent validation flash during keypad input - Enhanced limit order validation to require price parameter **Type System Updates:** ```typescript export type OrderParams = { // Existing fields... size: string; // Now derived, provider recalculates from usdAmount // New hybrid approach fields usdAmount?: string; // Primary source of truth priceAtCalculation?: number; // For slippage validation maxSlippageBps?: number; // Slippage tolerance (e.g., 100 = 1%) // Updated documentation slippage?: number; // Now defaults to ORDER_SLIPPAGE_CONFIG.DEFAULT_SLIPPAGE_BPS / 10000 }; ``` #### 4. Close Position Validation & Precision **Problem Addressed:** - Close positions were failing with "Minimum order size is $10" even when closing 100% of small positions (e.g., closing a $5.23 position) - Close position calculations used hardcoded decimal precision (6 decimals) instead of asset-specific `szDecimals` - As part of the USD-as-source-of-truth refactor, close position calculations needed the same precision improvements as order placement **Solution - Full vs Partial Close Distinction:** **Full Position Close (100%):** - Added `isFullClose` flag to `OrderParams` type - Set automatically when `size` parameter is omitted: `isFullClose: !params.size` - Skips USD validation and $10 minimum entirely - Allows closing positions of any size (e.g., $5.23 position) **Partial Position Close:** - Still enforces $10 minimum validation - Uses same USD validation logic as new orders - Requires `currentPrice` or `usdAmount` for validation **Close Amount Calculation Refactor:** - Migrated `calculateCloseAmountFromPercentage` to USD as source of truth - Added required `szDecimals` parameter (removed dangerous defaults) - Implemented post-rounding USD validation: ```typescript const actualUsd = tokenAmount * currentPrice; if (actualUsd < usdValue) { tokenAmount += 1 / multiplier; // Add 1 minimum increment } ``` - Now matches `calculatePositionSize` logic for consistency **Type Changes:** ```typescript export type OrderParams = { // ... existing fields isFullClose?: boolean; // Indicates closing 100% of position (skips validation) }; // calculateCloseAmountFromPercentage now requires szDecimals interface CloseAmountFromPercentageParams { percentage: number; positionSize: number; currentPrice: number; szDecimals: number; // REQUIRED - no longer optional } ``` **Files Changed:** - `controllers/types/index.ts` - Added `isFullClose` flag - `utils/positionCalculations.ts` - Refactored to use USD as source of truth with asset-specific precision - `Views/PerpsClosePositionView/PerpsClosePositionView.tsx` - Added `szDecimals` handling with loading state - `controllers/providers/HyperLiquidProvider.ts` - Updated validation to skip minimum for full closes #### 5. Position Size Calculation Changes **Rounding Behavior:** - Changed from `Math.floor` to `Math.round` in `calculatePositionSize` - More accurate position size calculation that rounds to nearest value - Aligned with provider's recalculation logic for consistency **Provider-Side Recalculation:** ```typescript // In HyperLiquidProvider.placeOrder() if (params.usdAmount && parseFloat(params.usdAmount) > 0) { const usdAmount = parseFloat(params.usdAmount); // Recalculate with fresh price finalPositionSize = usdAmount / currentPrice; // Apply same rounding as UI const multiplier = Math.pow(10, assetInfo.szDecimals); finalPositionSize = Math.round(finalPositionSize * multiplier) / multiplier; } ``` #### 6. User Experience Improvements **Input Handling:** - Removed optimization calls from percentage/slider/max buttons - Fixed input clamping to only apply for keypad input (not percentage/slider/max) - Reduced unnecessary re-renders and calculations - Skip validation during active input to prevent flickering error messages **Code Cleanup:** - Removed FinalizationRegistry polyfill from `shim.js` (no longer needed by updated dependencies) - Removed unused `findOptimalAmount` and `findHighestAmountForPositionSize` functions - Cleaned up debounced optimization logic from form handlers ### Migration Path **Backward Compatibility:** - `size` field still present in `OrderParams` for backward compatibility - Provider falls back to legacy size calculation if `usdAmount` is not provided - Existing orders and integrations continue to work **Hybrid Approach:** Orders now pass both `usdAmount` (primary) and `size` (derived): ```typescript const orderParams: OrderParams = { coin: 'BTC', isBuy: true, size: positionSize, // Kept for compatibility, recalculated by provider usdAmount: orderForm.amount, // USD as source of truth priceAtCalculation: assetData.price, // For validation maxSlippageBps: 100, // 1% tolerance // ... other fields }; ``` ### Files Changed **Core Logic (276 additions, 290 deletions):** - `app/components/UI/Perps/controllers/providers/HyperLiquidProvider.ts` (+148 lines) - Hybrid USD-based order placement with price validation - Standardized slippage across all order types - Position size recalculation at execution time - `app/components/UI/Perps/utils/orderCalculations.ts` (-149 lines) - Removed `findOptimalAmount` and `findHighestAmountForPositionSize` - Changed `Math.floor` to `Math.round` for position size calculation - `app/components/UI/Perps/hooks/usePerpsOrderForm.ts` (-71 lines) - Removed `optimizeOrderAmount` function and related logic - Simplified amount initialization - `app/components/UI/Perps/hooks/usePerpsOrderValidation.ts` (+28 lines) - Added `skipValidation` and `originalUsdAmount` parameters - Improved minimum order size validation with original USD input **UI Components:** - `app/components/UI/Perps/Views/PerpsOrderView/PerpsOrderView.tsx` (+/-54 lines) - Removed optimization calls from input handlers - Added `skipValidation` flag during input focus - Pass `usdAmount` and price validation params to provider - Fixed input clamping behavior **Configuration:** - `app/components/UI/Perps/constants/perpsConfig.ts` (+10 lines) - Added `ORDER_SLIPPAGE_CONFIG` constant - `app/components/UI/Perps/constants/hyperLiquidConfig.ts` (-1 line) - Removed legacy slippage configuration **Types & Validation:** - `app/components/UI/Perps/controllers/types/index.ts` (+9 lines) - Updated `OrderParams` type with USD-based fields - `app/components/UI/Perps/utils/hyperLiquidValidation.ts` (+9 lines) - Enhanced validation for limit orders - Added minimum order size tolerance - `app/components/UI/Perps/utils/hyperLiquidValidation.test.ts` (+29 lines) - Added tests for limit order price validation **Cleanup:** - `shim.js` (-18 lines) - Removed FinalizationRegistry polyfill ## **Changelog** CHANGELOG entry: Improved Perps order precision and validation by using USD amounts as source of truth and standardizing slippage management ## **Related issues** Fixes: [TAT-1902](https://consensyssoftware.atlassian.net/browse/TAT-1902) - Investigate and resolve order placement issue for specific token pairs **How this PR fixes TAT-1902:** The USD-as-source-of-truth refactor directly addresses order placement failures for specific token pairs by: - Recalculating position size at execution time with fresh market prices instead of using stale UI calculations - Using asset-specific `szDecimals` precision throughout (no more hardcoded 6 decimals) - Eliminating optimization logic that could produce invalid amounts near precision boundaries - Validating orders with the exact USD amount entered by the user, preventing precision loss from multiple conversions This ensures orders are calculated with the most current price and correct precision for each token pair, preventing the placement failures that occurred with the previous approach. ## **Manual testing steps** ```gherkin Feature: Perps Order Placement with USD as Source of Truth Scenario: User places a market order with precise USD amount Given user is on the Perps trading screen And user has sufficient balance When user enters "$100" USD amount via keypad And user selects "Market" order type And user taps "Place Order" Then order is placed with position size calculated from fresh market price And order execution succeeds without "insufficient margin" errors And no validation flickering occurs during input Scenario: User places order near minimum amount threshold Given user is on the Perps trading screen And market price causes calculated value to be near $10 minimum When user enters an amount that rounds to ~$9.99-$10.01 And user places the order Then validation passes with 1% tolerance And no flickering validation errors appear Scenario: Price moves during order placement Given user has entered order details And calculated position size at price $50,000 When market price moves to $50,500 (>1% move) And user places the order Then order is rejected with "Price moved too much" error And user is prompted to review and resubmit Scenario: User places limit order without price Given user is on the Perps trading screen And user selects "Limit" order type And user does not enter a limit price When user attempts to place order Then validation error displays "Price is required for limit orders" Scenario: User uses percentage buttons Given user is on the Perps trading screen And user has $1000 available balance When user taps "25%" button Then amount field shows "$250" And no optimization is triggered And position size is calculated correctly Scenario: User adjusts amount with slider Given user is on the Perps trading screen When user drags the amount slider Then amount updates in real-time And validation is skipped during interaction And validation applies after slider is released Scenario: User enters amount exceeding maximum Given user has $1000 available balance at 10x leverage And maximum possible order is $10,000 When user enters "$15,000" via keypad And user dismisses the keypad Then amount is automatically clamped to "$10,000" And validation message explains the limit Scenario: User closes 100% of a position worth less than minimum Given user has an open position worth $5.23 And minimum order size is $10 When user taps "Close Position" button And selects "100%" (full close) And confirms the close Then position closes successfully And no minimum order size error appears And full position value is returned Scenario: User closes partial position below minimum Given user has an open position worth $100 And minimum order size is $10 When user attempts to close $8 worth of the position And confirms the close Then validation error displays "Minimum order size is $10" And close operation is prevented ``` ## **Screenshots/Recordings** ### **Before** - Orders occasionally failed with "insufficient margin" despite UI showing valid amounts - Validation messages flickered during input on low-priced tokens - Complex optimization logic ran on every input change - Position size calculated once in UI, potentially stale at execution ### **After** - Consistent order execution with USD as source of truth - No validation flickering with 1% tolerance on minimum amounts - Simplified input handling without optimization overhead - Position size recalculated with fresh price at execution time - Price staleness validation prevents execution with stale prices <!-- Add screenshots/recordings here if available --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- ## **Technical Notes for Reviewers** ### Critical Changes to Review 1. **Rounding Change in `calculatePositionSize`** - Changed from `Math.floor` to `Math.round` - Verify this doesn't cause issues with existing positions or orders - Check that rounding behavior matches exchange requirements 2. **Backward Compatibility** - `OrderParams.size` still present but recalculated by provider - Verify existing integrations continue to work - Test with and without `usdAmount` parameter 3. **Slippage Validation** - Price staleness check may reject valid orders in volatile markets - Default 1% tolerance (100 bps) - verify this is appropriate - Check error messages are clear to users 4. **Minimum Order Size Validation** - USD as source of truth - validates exact user input ($10 ≥ $10) - No tolerance needed when using usdAmount parameter - **Full position closes (100%)** skip validation entirely via `isFullClose` flag - **Partial position closes** enforce $10 minimum validation - **New positions** enforce $10 minimum validation - Close position calculations use same USD validation logic as order placement 5. **Input Clamping Logic** - Now only clamps for keypad input, not percentage/slider/max - Verify this doesn't break max amount validation - Test with various input methods ### Testing Recommendations - Test with various token prices (low, medium, high) - Test near minimum order size ($10) with price fluctuations - Test with high leverage where rounding matters more - Test order placement during price volatility - Test limit orders with missing/invalid prices - Verify no "insufficient margin" errors for valid amounts - Check validation doesn't flicker during keypad input [TAT-1902]: https://consensyssoftware.atlassian.net/browse/TAT-1902?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Switches order/close flows to USD-as-source-of-truth with provider-side size recalculation and unified slippage, improves validation/precision, removes optimization logic, and updates hooks/tests/docs. > > - **Core trading/provider**: > - Use USD as source of truth; provider recalculates size at execution with fresh price and asset `szDecimals` (`HyperLiquidProvider.ts`). > - Add slippage config via `ORDER_SLIPPAGE_CONFIG` (default 100 bps) and price-staleness validation; pass `usdAmount`, `priceAtCalculation`, `maxSlippageBps` through `OrderParams`. > - Refactor order build/format helpers into `orderCalculations` (`calculateFinalPositionSize`, `calculateOrderPriceAndSize`, `buildOrdersArray`). > - Support full-close bypass of $10 minimum via `isFullClose`; propagate slippage params in close flows. > - **Validation & precision**: > - `calculatePositionSize`/close calculations use asset precision, round to nearest, and ensure post-rounding USD meets target. > - `validateOrder` now validates minimums from USD, requires price for limit orders, and tolerates full closes. > - Remove `findOptimalAmount`/related logic and old slippage from `hyperLiquidConfig`. > - **UI/hooks**: > - `PerpsOrderView`/`PerpsClosePositionView`: pass USD + slippage params; skip validation during input; clamp only for keypad; use market data with fallback decimals. > - `usePerpsMarketData` accepts `{ asset, showErrorToast }` and auto-toasts on errors; expose loading. > - `usePerpsOrderValidation`/`usePerpsClosePositionValidation`: add `skipValidation`, use original USD for min checks. > - **Types/constants**: > - Extend `OrderParams`/`ClosePositionParams` with USD/slippage/full-close fields; add `DECIMAL_PRECISION_CONFIG.FALLBACK_SIZE_DECIMALS` and `ORDER_SLIPPAGE_CONFIG`. > - **Tests & docs**: > - Update extensive tests to new params, rounding, and hook signatures; adjust provider tests for price-required errors. > - Refresh trading guide (market order/slippage sections) and fix reference paths. > - **Cleanup**: > - Remove FinalizationRegistry polyfill from `shim.js`; simplify order form by dropping optimization APIs. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fda1210. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: dylanbutler1 <99672693+dylanbutler1@users.noreply.github.com>
…22392) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR aims to fix recipient input to show multiline for selected address in send flow ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fix recipient to be shown multi-line in send flow ## **Related issues** Fixes: #22207 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="568" height="1084" alt="Screenshot 2025-11-10 at 12 03 50" src="https://github.com/user-attachments/assets/f8f0da96-2505-4c76-b77c-f904fcab3d6d" /> ### **After** <img width="568" height="1084" alt="Screenshot 2025-11-10 at 12 03 43" src="https://github.com/user-attachments/assets/56c76b7c-a0c9-4640-9f02-bc3b446eed68" /> ## **Pre-merge author checklist** - [X] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I’ve included tests if applicable - [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces direct TextField props with a custom Input element to force single-line recipient addresses and prevent multiline behavior. > > - **Confirmations › RecipientInput (`app/components/Views/confirmations/components/recipient-input/recipient-input.tsx`)** > - Use `TextField` `inputElement` with `foundation/Input` to control behavior. > - Configure single-line input: `multiline={false}`, `numberOfLines={1}`, `scrollEnabled={false}`, `textAlignVertical="center"`, `textBreakStrategy="simple"`. > - Move input props (value, change handlers, autocorrect/spellcheck/autocomplete/capitalize, placeholder, autofocus, testID) onto `Input`. > - Apply `INPUT_STYLE_OVERRIDE` to remove height/lineHeight and pad adjustments; disable state styles; set `textVariant` via `TOKEN_TEXTFIELD_INPUT_TEXT_VARIANT`. > - Keep start/end accessories (To label, Clear/Paste buttons) unchanged. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e06f20c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR aims to add PPOM validation requests for deeplinks. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: MetaMask/mobile-planning#2370 Fixes: #17358 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [X] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I’ve included tests if applicable - [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Integrates PPOM validation into deeplink transfer/approve flows, generating a securityAlertId and passing it to addTransaction, with refactors and tests. > > - **Deeplink handling (`app/components/Views/confirmations/utils/deeplink.ts`)**: > - Add `validateWithPPOM` to build a PPOM request (with uuid-based `securityAlertId`) and call `ppomUtil.validateRequest`. > - Pass returned `securityAlertResponse` to `addTransaction` for both native and ERC20 transfers. > - Refactor tx construction to derive `txParams` and `transactionType`; downgrade duplicate-request log from error to log. > - **Approve flow (`app/core/DeeplinkManager/TransactionManager/approveTransaction.ts`)**: > - Compute `chainId`/`networkClientId`, call `validateWithPPOM`, and include `securityAlertResponse` in `addTransaction`. > - **Tests**: > - Extend deeplink and approve tests to mock PPOM and UUID, assert PPOM validation payload, `securityAlertResponse`, and `networkClientId` wiring. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit daa4941. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Fix scrolling in the MetaMask Pay asset picker on Android. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [#6147](MetaMask/MetaMask-planning#6147) ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Switches asset picker and network filter to use react-native-gesture-handler ScrollView to fix Android scrolling. > > - **Mobile UI**: > - Replace `react-native` `ScrollView` with `react-native-gesture-handler` in `app/components/Views/confirmations/components/network-filter/network-filter.tsx` and `app/components/Views/confirmations/components/send/asset/asset.tsx`. > - Minor `ScrollView` prop formatting cleanup in `asset.tsx`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit a7e0901. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Show additional details in Predict claim confirmation if single won position. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [6004](MetaMask/MetaMask-planning#6004) ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** <img width="300" alt="Claim Single" src="https://github.com/user-attachments/assets/088c99d2-d3b7-4852-9009-357ad4ccd546" /> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Enhances Predict claim footer to display detailed info for a single win and refactors component structure with accompanying tests. > > - **Predict claim footer** (`predict-claim-footer.tsx`): > - Show single-win details: large token avatar, market title, formatted fiat amount, and outcome. > - Refactor into `SingleWin` and `MultipleWinnings` subcomponents; memoize fiat formatting; return null when no won positions. > - **Tests**: > - Add tests for single-win extra info, avatar count (max 3), button press, and fallback selected address. > - Update mocks/render helper to support `singlePosition` and `accountMock`. > - Remove predict-claim footer render check from generic `Footer` tests and drop unused `TransactionType` import. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8073f69. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…22517) ## **Description** This PR fixes an issue in the Perps Market Tabs component where the TabsList wasn't properly re-rendering when the number of visible tabs changed. ## **Changelog** CHANGELOG entry: Fixed an issue where perps market tabs would not update correctly when the number of visible tabs changed ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TAT-1982 ## **Manual testing steps** ```gherkin Feature: Perps Market Tabs Rendering Scenario: user switches between market states that affect tab visibility Given user is on the perps market details view with active position When user closes their position or opens new positions Then the tabs should correctly update to reflect the current state (position tab should appear/disappear) And the active tab selection should remain consistent ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> No visible change ### **After** <!-- [screenshots/recordings] --> No visible change ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Ensure `TabsList` remounts when the number of visible tabs changes by incorporating `tabsToRender.length` into the component key. > > - **Perps UI**: > - **Tabs re-rendering**: Update `tabsKey` in `PerpsMarketTabs.tsx` to `tabs-${tabs.length}-${tabsToRender.length}` so `TabsList` remounts when the visible tab count changes. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e03f2b2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
- Introduced PortManager to handle port allocation and release for
various servers.
- Updated Ganache, MockServerE2E, DappServer, CommandQueueServer,
FixtureServer, and AnvilManager to utilize PortManager for setting and
releasing ports.
- Added methods to set server ports and handle server status in
respective classes.
- Implemented retry logic for starting resources with automatic port
management to avoid conflicts.
- Updated FixtureUtils to include new port management functions and
ensure correct RPC URLs are used based on allocated ports.
- Update swaps tests to use Anvil (from ganache)
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds PortManager-driven dynamic port allocation with retries and
platform handling, refactors test servers/utilities to use it, migrates
swaps tests to Anvil, and standardizes “Network fee” casing.
>
> - **E2E Infra (Port Management)**:
> - Introduces `PortManager` for dynamic/random port allocation
(single/multi-instance), release, and BrowserStack fallbacks; adds
robust retry start helpers (`startResourceWithRetry`,
`startMultiInstanceResourceWithRetry`).
> - Implements Android `adb reverse` mapping, iOS LaunchArgs, and
MockServer host-side fallback→actual port translation.
> - **Server/Utility Refactors**:
> - Update `Ganache`, `AnvilManager`, `FixtureServer`,
`CommandQueueServer`, `DappServer`, `MockServerE2E` to `setServerPort`,
track status, and release ports; `DappServer` supports multi-instance.
> - Revamps `FixtureUtils`/`FixtureHelper` APIs (`getDappUrl*`,
`get*PortForFixture`, RPC/Dapp URL rewrites) and improves
network-store/shim host resolution.
> - **Tests**:
> - New comprehensive `PortManager.test.ts`.
> - Migrate swaps tests to Anvil; update fixtures and helpers to new
APIs; remove manual reverse logic.
> - **UX/Text**:
> - Standardize casing to `Network fee` across tests and
`locales/languages/en.json`.
> - **Misc**:
> - Adjust allowlist/mocks; minor README formatting.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f63e958. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: fix error message when trying to import an SRP with an account that is already imported via private key ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUL-491 ## **Manual testing steps** 1. Import private key account 2. Import SRP that includes this private key account 3. Verify that the error message "The account you are trying to import is a duplicate." is shown ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <img width="925" height="903" alt="image" src="https://github.com/user-attachments/assets/77abb409-feac-4ba4-92bd-387d122928dd" /> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds explicit handling and user-facing message when an SRP import fails due to a duplicate account, with tests and i18n updates. > > - **Import SRP View (`app/components/Views/ImportNewSecretRecoveryPhrase/index.tsx`)**: > - Refactor error handling to `switch` and add case for `KeyringController - The account you are trying to import is a duplicate`, showing `error_duplicate_account` alert. > - **Tests (`app/components/Views/ImportNewSecretRecoveryPhrase/index.test.tsx`)**: > - Add test to assert duplicate account import error triggers the correct alert. > - **Localization (`locales/languages/en.json`)**: > - Add `import_new_secret_recovery_phrase.error_duplicate_account` copy. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f43d802. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** As part of developing the "Trending" feature we needed to add a global search that would allow searching amongst trending tokens, perps, trending predictions... I have developed a MODULAR search hook and global search that allows searching across all existing sections and allows for easy integration of new sections. If a new section is added, the user will have to only modify the configuration in `exploreSearchConfig` like this: <img width="387" height="328" alt="image" src="https://github.com/user-attachments/assets/e00ce4fb-3831-422e-80a3-30d2436cddad" /> and add the necessary hook inside `useExplorerSearch`: <img width="416" height="449" alt="image" src="https://github.com/user-attachments/assets/78366050-4ab8-4859-ad09-095077be89cf" /> Everything else is handled automatically which makes it **easy** for developers to add new configurations <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: added new trending search functionality ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-1528 & https://consensyssoftware.atlassian.net/browse/ASSETS-1527 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** https://github.com/user-attachments/assets/d912d5d0-4cd1-45c9-8a94-459d437f03aa ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces an Explore Search flow with a modular search hook, UI components, navigation, i18n, and tests, enabling search across tokens, perps, and predictions from the Trending tab. > > - **Trending / Explore Search**: > - **UI**: > - Add `ExploreSearchBar` and `ExploreSearchScreen` with `ExploreSearchResults` list (headers, items, skeletons). > - Integrate search entry in `TrendingView` (button + navigation), wrap with `PerpsStreamProvider`. > - **Hook & Config**: > - Add generic `useExploreSearch` (200ms debounce, top-3 on empty, per-section filtering). > - Define configurable sections in `exploreSearchConfig` for `tokens`, `perps`, `predictions` with item renderers and key extractors. > - **Navigation**: > - Add route `Routes.EXPLORE_SEARCH`; register in `TrendingView` stack; update imports in `MainNavigator`. > - **i18n**: > - Extend `trending` strings: `search_placeholder`, `perps`, `predictions`, `no_results`. > - **Tests**: > - Add tests for `ExploreSearchBar`, `ExploreSearchResults`, `useExploreSearch`, and update `TrendingView` tests for search button and navigation. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b35671b. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** ### Summary Adds Segment analytics tracking for QR Scanner usage to measure feature adoption and understand user scanning patterns. ### Events Added - **QR Scanner Opened** - Tracks when QR scanner is opened with camera permission granted - **QR Scanned** - Tracks all QR code scan attempts with success/failure, type classification, and detailed scan results ### Properties **QR Scanned** includes: - `scan_success` (boolean) - Technical success: camera successfully read the QR code - `qr_type` (string) - Classification: `"seed phrase"` | `"private key"` | `"send flow"` | `"wallet connect"` | `"deeplink"` | `"url"` - `scan_result` (string) - Functional outcome: `"completed"` | `"deeplink_handled"` | `"url_navigation_confirmed"` | `"unrecognized_qr_code"` | `"invalid_address_format"` | `"url_navigation_cancelled"` | `"wallet_locked"` ### Use Cases - Measure scanner success rate (filter by `scan_result` to exclude failures) - Understand QR type distribution (`qr_type` breakdown) - Debug scan failures (`scan_result` analysis) - Improve UX by identifying common failure patterns - Track WalletConnect connection initiation via QR codes ### Implementation Details #### QR_SCANNER_OPENED - Fires once per scanner session when permission is granted and camera is available - Includes global properties only #### QR_SCANNED - Tracks all 6 QR code types with appropriate success/failure states: - Seed Phrase - Private Key - Send Flow - Wallet Connect - Deeplink - URL Segment PR: Consensys/segment-schema#360 ## **Changelog** CHANGELOG entry: Added segment events for QR scanning ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-66 ## **Manual testing steps** ```gherkin Feature: QR Scanner Metrics Tracking Scenario: QR Scanner Opened event fires when scanner is accessed Given the user is on the MetaMask Mobile homepage And camera permissions are granted When user taps the QR scanner icon Then the QR scanner opens And "QR Scanner Opened" event is tracked with no custom properties And the event appears in console logs and Segment debugger Scenario: user scans a seed phrase QR code Given the QR scanner is open And a QR code containing a 12-word seed phrase is displayed When user scans the seed phrase QR code Then "QR Scanned" event is tracked And scan_success property is true And qr_type property is "seed phrase" Scenario: user scans a private key QR code Given the QR scanner is open And a QR code containing "0x" followed by 64 hex characters is displayed When user scans the private key QR code Then "QR Scanned" event is tracked And scan_success property is true And qr_type property is "private key" Scenario: user scans a valid Ethereum address in send flow Given the user is in the Send Flow screen And user taps the QR scanner icon And a QR code containing a valid Ethereum address is displayed When user scans the address QR code Then "QR Scanned" event is tracked And scan_success property is true And qr_type property is "send flow" Scenario: user scans an invalid address in send flow Given the user is in the Send Flow screen And user taps the QR scanner icon And a QR code containing invalid address text is displayed When user scans the invalid QR code Then "QR Scanned" event is tracked And scan_success property is false And qr_type property is "send flow" And an error alert is displayed Scenario: user scans a WalletConnect URI Given the QR scanner is open And a QR code containing a WalletConnect URI (wc:...) is displayed When user scans the WalletConnect QR code Then "QR Scanned" event is tracked And scan_success property is true And qr_type property is "wallet connect" Scenario: user scans a MetaMask deeplink Given the QR scanner is open And a QR code containing "metamask-sdk://" or "metamask-sync:" is displayed When user scans the deeplink QR code Then "QR Scanned" event is tracked And scan_success property is true And qr_type property is "deeplink" Scenario: user scans a URL and confirms navigation Given the QR scanner is open And a QR code containing "https://example.com" is displayed When user scans the URL QR code And user taps "Continue" on the confirmation dialog Then "QR Scanned" event is tracked And scan_success property is true And qr_type property is "url" Scenario: user scans a URL and cancels navigation Given the QR scanner is open And a QR code containing "https://example.com" is displayed When user scans the URL QR code And user taps "Cancel" on the confirmation dialog Then "QR Scanned" event is tracked And scan_success property is false And qr_type property is "url" ``` ## **Screenshots/Recordings** ### Seed Phrase Flow https://github.com/user-attachments/assets/6f8357c3-f1e4-467b-8c6a-9188a71948f4 ### Private Key Flow https://github.com/user-attachments/assets/1ce6f4cf-62e7-4bde-bce5-8d14bf9fba50 ### Send Flow - Valid Address __Send flow is currently broken there is a PR [here](#21498) to fix the issue. The video is just a demonstration of the event being tracked__ https://github.com/user-attachments/assets/909d5687-9789-41b5-be45-4503a1bb0e53 ### Send Flow - Unknown Address https://github.com/user-attachments/assets/fd15c33c-e90a-4427-a7ed-684a741a075f ### Send Flow - Invalid Address https://github.com/user-attachments/assets/34f27530-b1d6-4035-9713-19955c501090 ### Wallet Connect https://github.com/user-attachments/assets/b41f9fcc-a6a1-4440-9bba-63be4305ad4e ### SDK ### Website - Accept https://github.com/user-attachments/assets/d7f00d09-a03a-4e6c-9056-99575ed2302d ### Website - Cancel https://github.com/user-attachments/assets/2c3d9cff-36cd-475c-958e-e16034030e46 ### **Before** `~` ### **After** `~` ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds MetaMetrics tracking for QR Scanner open/scan with standardized properties and QR type detection, plus comprehensive tests and event definitions. > > - **Analytics**: > - Add `QR_SCANNER_OPENED` and `QR_SCANNED` to `core/Analytics/MetaMetrics.events.ts`. > - Track scanner open when permission granted and camera available. > - Track scans with properties: `scan_success`, `qr_type`, `scan_result` across types (`seed phrase`, `private key`, `send flow`, `wallet connect`, `deeplink`, `url`), including outcomes (e.g., URL confirm/cancel, wallet locked, invalid address, deeplink handled). > - **QR Scanner**: > - New `app/components/Views/QRScanner/constants.ts` for event keys, QR types, and scan result values. > - New `getQRType` in `app/components/Views/QRScanner/utils.ts` to classify scanned content. > - Update `app/components/Views/QRScanner/index.tsx` to emit events, handle URL redirection flow, SDK/deeplink handling, and wallet-locked checks; minor typing/refactors. > - **Tests**: > - Expand `index.test.tsx` to validate event emission for all paths. > - Add `utils.test.ts` to verify `getQRType` classification logic. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e419028. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR enables live PnL (Profit and Loss) updates in the Perps Market Tabs by subscribing to real-time price updates from the WebSocket stream. ## **Changelog** CHANGELOG entry: Fixed live PnL updates in Perps market tabs to reflect real-time price changes ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TAT-1946 ## **Manual testing steps** ```gherkin Feature: Live PnL updates in Perps Market Tabs Scenario: user views position with live PnL updates Given user has an open perpetual position And user is on the Perps Market Tabs screen When market price changes Then the unrealized PnL and ROE values update in real-time And the position card reflects current market conditions ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** No visible changes ### **After** No visible changes ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Enable live PnL updates by passing `useLivePnl: true` to `usePerpsLivePositions` in `PerpsMarketTabs.tsx`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 32657d9. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Nicholas Smith <nick.smith@consensys.net>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR introduces **AppStateAPI**, a new centralized API for monitoring React Native app state changes (foreground/background/inactive) and managing lock timers. ### **Reason for the change** Currently, app state monitoring is scattered across the codebase with direct React Native `AppState` imports in multiple components. This creates tight coupling and makes it difficult to: - Track which components are monitoring app state - Test app state behavior consistently - Manage lock timers in a centralized way - Ensure proper cleanup of native listeners ### **The improvement/solution** **AppStateAPI** provides a clean, singleton-based API with the following benefits: 1. **Centralized Monitoring**: Single source of truth for app state changes 2. **EventEmitter Pattern**: Components can subscribe to specific events (`foreground`, `background`, `inactive`, `change`) without tight coupling 3. **Separation of Concerns**: The API only monitors and emits events—it does NOT perform locking. State machines/sagas handle actual locking logic 4. **Lock Timer Management**: Built-in timer functionality for auto-lock features with background timer support 5. **Clean Lifecycle**: Explicit `initialize()` and `cleanup()` methods with proper native listener management 6. **Type Safety**: Full TypeScript implementation with exported types ### **Key Features** - **App State Events**: `foreground`, `background`, `inactive`, `change` - **Lock Timer**: `startLockTimer(duration, callback)`, `clearLockTimer()`, `getLockTimerRemaining()`, `isLockTimerActive()` - **State Queries**: `getCurrentAppState()`, `isAppInForeground()`, `isAppInBackground()`, `isAppInactive()` - **Lifecycle**: `initialize()`, `cleanup()`, `isInitialized()` ### **Architecture Summary** | Component | Status | Lines | Purpose | |------------------------|--------|-------|----------------------------------| | AppStateAPI | ✅ New | 267 | Monitor app state & lock timers | | Authentication.ts | ✅ Existing | 1230 | Keep using (works well) | | State Machines (Sagas) | 🔄 Update | 234 | Will use AppStateAPI events | | LockManagerService |⚠️ Deprecate | 122 | Gradually migrate away | This PR includes debug instrumentation in `Root/index.tsx` for manual testing (dev mode only). ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: [Add issue number here] ## **Manual testing steps** ```gherkin Feature: AppStateAPI monitors app state changes Scenario: Developer tests app state monitoring in development mode Given the app is running in development mode And AppStateAPI is initialized in Root component When the app is launched Then console logs should show "APPSTATEAPI: 🔵 Initializing AppStateAPI for manual testing" And console logs should show "APPSTATEAPI: 🔵 Starting 10-second lock timer" And console logs should display current app state as "active" Scenario: Developer backgrounds the app Given the app is running in foreground And AppStateAPI is initialized When the developer backgrounds the app Then console logs should show "APPSTATEAPI: 🔴 App BACKGROUNDED" And the background event should be emitted with state "background" Scenario: Developer foregrounds the app Given the app is running in background And AppStateAPI is initialized When the developer brings the app to foreground Then console logs should show "APPSTATEAPI: 🟢 App FOREGROUNDED" And the foreground event should be emitted with state "active" Scenario: Lock timer expires while app is backgrounded Given the app is running And a 10-second lock timer has been started When the developer backgrounds the app for more than 10 seconds Then console logs should show "APPSTATEAPI: ⏰ Lock timer EXPIRED" And the timer callback should be invoked Scenario: Developer checks AppStateAPI state queries Given the app is running And AppStateAPI is initialized When the developer views the console logs Then logs should show "Is in foreground?" with a boolean value And logs should show "Lock timer active?" with a boolean value And logs should show the current app state Scenario: AppStateAPI cleanup on unmount Given the app is running with AppStateAPI initialized When the Root component unmounts Then console logs should show "Cleaning up AppStateAPI" And all event listeners should be removed And lock timers should be cleared ``` ## **Screenshots/Recordings** https://github.com/user-attachments/assets/b9dfe51e-9ab9-45cc-802d-7f5fd9281c38 ### **Before** No centralized app state monitoring—components directly import `AppState` from React Native. ### **After** New `AppStateAPI` provides centralized monitoring with console output in dev mode: <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduce a singleton AppState service that emits app state events and manages a lock timer, with comprehensive tests and exports. > > - **Core**: > - **`app/core/AppStateService/AppStateService.ts`**: New singleton `AppStateServiceImplementation` (EventEmitter-based) to monitor React Native `AppState` and emit `foreground`, `background`, `inactive`, and `change` events. > - Provides lifecycle methods: `initialize()`, `cleanup()`, `isInitialized()`. > - Adds lock timer utilities: `startLockTimer()`, `clearLockTimer()`, `getLockTimerRemaining()`, `isLockTimerActive()` using `react-native-background-timer`. > - Exports singleton `AppStateService` and `AppStateStatus` type. > - **Exports**: > - **`app/core/AppStateService/index.ts`**: Re-exports service, implementation, and types. > - **Tests**: > - **`app/core/AppStateService/AppStateService.test.ts`**: Comprehensive unit tests mocking React Native and background timer to verify initialization/cleanup, event emissions, lock timer behavior, and state query helpers. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 574d3df. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
Current BUGBOT rules and are too verbose and don't consistently run in
the pipeline without manual intervention. This change updates the file
structure as per the Cursor docs and simplifies the rule.
1. Changes BUGBOT file location for more consistent ci running
2. Replaces verbose rules with simple rules and adds markdown links so
Cursor can read them.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
3. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
This test fork repo shows the rule now hits every Unit Test violation in
the Unit Testing Guidelines. Including
Test naming violations
AAA pattern violations
TypeScript type violations
Import/require violations
Test isolation violations
Assertion quality violations
Test complexity violations
https://github.com/michaelmccallam/metamask-mobileBugbotTest/pull/6/files
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
Didn't pick up on the rules consistently
<!-- [screenshots/recordings] -->
### **After**
Now picks up on each rule in the Unit Testing Guidelines and calls it
out in the comments.
<img width="730" height="441" alt="Screenshot 2025-11-08 at 09 50 23"
src="https://github.com/user-attachments/assets/ffd7a768-d012-49ae-92ec-e05a67266c5e"
/>
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Moves BUGBOT rules to `.cursor/BUGBOT.md` and streamlines content,
updating test file pattern and guideline link.
>
> - **BUGBOT rules**:
> - **Relocation**: Move from `.cursor/rules/BUGBOT.md` to
`.cursor/BUGBOT.md`.
> - **Simplification**: Replace verbose rule set with concise core
mission and minimal execution protocol.
> - **Testing pattern**: Update naming pattern to
``*.test.{ts,tsx,js,jsx}``.
> - **Guidelines link**: Reference `rules/unit-testing-guidelines.mdc`
from new location.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6949b1f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
# Predict Buy: Rewards Display and Fee Consolidation ## Overview This PR adds rewards point estimation and consolidates fee display in the Predict Buy confirmation screen. Users can now see estimated MetaMask Rewards points they'll earn from their transaction, and view detailed fee breakdowns through an intuitive bottom sheet. CHANGELOG entry: null https://github.com/user-attachments/assets/cf20a4e3-1375-4f9b-97ff-c75a3d68f737 ## Changes ### 🎁 Rewards Integration - **Added "Est. points" row** to the Predict Buy confirmation screen - Displays estimated rewards points based on MetaMask fee - **Calculation**: `Math.round(metamaskFee * 100)` (1 point per cent spent on MM fee) - Position: Last row after "Total" - White text with gray info icon for consistency - Reuses `RewardsAnimations` component from Swap/Bridge features - Conditional display based on `rewardsEnabled` feature flag and transaction amount ### 💰 Fee Display Consolidation - **Consolidated two fee rows into single "Fees" row** - Previously: Separate "Provider fee" and "MetaMask fee" rows - Now: Single "Fees" row showing sum of both fees - Added gray info icon that opens detailed breakdown - **New Fee Breakdown Bottom Sheet** (`PredictFeeBreakdownSheet`) - Displays individual fee breakdown: - Polymarket fee (provider fee) - MetaMask fee - Opens when user taps info icon next to "Fees" - Closes without navigating back (uses `shouldNavigateBack={false}`) ### 🎨 UI/UX Improvements - **Fee Summary Row Order**: 1. Fees (consolidated, with info icon) 2. Total 3. Est. points (when rewards enabled) - **Styling**: - Est. points text: White (`TextColor.Default`) - Info icons: Gray (`IconColor.Alternative`) - Consistent with design system ## Technical Details ### Files Modified #### Components - **`PredictBuyPreview.tsx`** - Import `selectRewardsEnabledFlag` selector - Calculate `estimatedPoints` from `metamaskFee` - Add `isFeeBreakdownVisible` state - Add `handleFeesInfoPress` and `handleFeeBreakdownClose` callbacks - Pass rewards props to `PredictFeeSummary` - Conditionally render `PredictFeeBreakdownSheet` - **`PredictFeeSummary.tsx`** - Remove individual fee rows - Add consolidated "Fees" row with `ButtonIcon` - Calculate `totalFees = providerFee + metamaskFee` - Move rewards row to last position (after Total) - Update text colors (white for Est. points label) - Add `onFeesInfoPress` callback prop #### New Files - **`PredictFeeBreakdownSheet.tsx`** - Bottom sheet component for fee breakdown - Displays provider and MetaMask fees separately - Uses `shouldNavigateBack={false}` to prevent parent modal closure - Accepts `onClose` callback - **`PredictFeeBreakdownSheet/index.ts`** - Export file for new component #### Localization - **`locales/languages/en.json`** ```json { "predict.fee_summary.fees": "Fees", "predict.fee_summary.provider_fee_label": "Polymarket fee", "predict.fee_summary.estimated_points": "Est. points", "predict.fee_summary.points_tooltip": "Points", "predict.fee_summary.points_tooltip_content_1": "Points are how you earn MetaMask Rewards for completing transactions, like when you swap, bridge, or predict.", "predict.fee_summary.points_tooltip_content_2": "Keep in mind this value is an estimate and will be finalized once the transaction is complete. Points can take up to 1 hour to be confirmed in your Rewards balance." } ``` ### Tests #### New Tests (22 total) - **`PredictFeeSummary.test.tsx`** (12 tests) - Consolidated fees display and calculation - Fees info icon callback handling - Rewards row conditional rendering - Rewards row positioning - Edge cases (zero fees, missing callbacks) - **`PredictFeeBreakdownSheet.test.tsx`** (10 tests - New file) - Bottom sheet rendering - Fee display (Polymarket and MetaMask) - `shouldNavigateBack` behavior - Close callback handling - Ref methods exposure - **`PredictBuyPreview.test.tsx`** (10 new tests) - Rewards calculation formula - Rewards point rounding - Feature flag conditional display - Fee breakdown sheet visibility - Loading state propagation #### Updated Tests (1) - Fixed existing test to expect "Fees" instead of "Provider fee" **Total Test Results**: 2,038 tests passing ✅ ## Rewards Calculation Logic ```typescript // Formula: 1 point per cent spent on MetaMask fee const estimatedPoints = useMemo( () => Math.round(metamaskFee * 100), [metamaskFee], ); // Display conditions const shouldShowRewards = rewardsEnabled && currentValue > 0; ``` ### Examples: - MetaMask fee: $0.50 → **50 points** - MetaMask fee: $1.23 → **123 points** - MetaMask fee: $0.00 → **0 points** ## Component Reusability This implementation reuses existing components: - ✅ `RewardsAnimations` (from Bridge/Swap) - ✅ `KeyValueRow` (component library) - ✅ `ButtonIcon` (design system) - ✅ `BottomSheet` (design system) - ✅ Design system tokens (`TextColor`, `IconColor`) ## Feature Flags - **Rewards display**: Controlled by `selectRewardsEnabledFlag` - **Fee breakdown**: Always available ## Testing Checklist - [x] Unit tests for all new components - [x] Unit tests for modified components - [x] All existing tests passing (2,038 tests) - [x] No linter errors - [x] Tests follow AAA pattern - [x] Tests follow project guidelines (no "should" in names) - [x] Edge cases covered (zero values, missing callbacks, etc.) ## Manual Testing ### Test Scenarios 1. **Rewards Display** - [ ] Verify Est. points row appears when rewards enabled - [ ] Verify points calculation: fee * 100 rounded - [ ] Verify Est. points row does NOT appear when rewards disabled - [ ] Verify Est. points row does NOT appear when amount is 0 2. **Fee Consolidation** - [ ] Verify single "Fees" row shows sum of provider + MetaMask fees - [ ] Verify info icon appears next to "Fees" label - [ ] Verify tapping info icon opens bottom sheet - [ ] Verify bottom sheet shows individual fee breakdown 3. **Bottom Sheet Behavior** - [ ] Verify bottom sheet displays "Polymarket fee" and "MetaMask fee" - [ ] Verify closing bottom sheet does NOT close parent modal - [ ] Verify bottom sheet closes on swipe down - [ ] Verify bottom sheet closes on backdrop tap 4. **Visual/Styling** - [ ] Verify Est. points text is white - [ ] Verify all info icons are gray - [ ] Verify row order: Fees → Total → Est. points - [ ] Verify layout on different screen sizes ## Before/After ### Before ``` Provider fee $0.10 MetaMask fee $0.04 Total $10.14 ``` ### After ``` Fees [i] $0.14 ← Tappable info icon Total $10.14 Est. points [i] 14 ← New rewards row (white text) ``` ### Fee Breakdown Sheet (when tapping [i]) ``` ╔════════════════════════╗ ║ Fees ║ ╠════════════════════════╣ ║ Polymarket fee $0.10 ║ ║ MetaMask fee $0.04 ║ ╚════════════════════════╝ ``` ## Commit History 1. `feat: Add rewards row to Predict Buy confirmation screen` - Initial rewards implementation 2. `refactor: Consolidate fee rows and add breakdown sheet` - Fee consolidation 3. `refactor: Move Est. points row to end and use white text` - Final positioning and styling 4. `test: Add comprehensive tests for rewards and fee breakdown features` - Complete test coverage ## Related Issues/PRs - Related to rewards feature integration - Consistent with Swap/Bridge rewards display patterns ## Checklist - [x] Code follows project coding guidelines - [x] Code follows React Native UI development guidelines - [x] Used design system components (`@metamask/design-system-react-native`) - [x] Used Tailwind CSS with `useTailwind()` hook - [x] No StyleSheet.create() used - [x] Proper TypeScript types (no `any`) - [x] Comprehensive unit tests added - [x] All tests passing - [x] No linter errors - [x] Localization strings added - [x] Feature flag integrated - [x] Component reusability maintained - [x] Follows AAA test pattern - [x] No breaking changes <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds rewards point estimation and consolidates fee display with a tappable fees breakdown sheet in Predict Buy. > > - **Predict UI**: > - `PredictFeeSummary`: Replace separate fee rows with a single "Fees" row (info icon), display total fees, and add "Est. points" row using `RewardsAnimations`. > - `PredictBuyPreview`: Compute `estimatedPoints = Math.round(metamaskFee * 100)`, gate rewards by `selectRewardsEnabledFlag`, and open fee breakdown via `onFeesInfoPress`; pass rewards/fees props. > - **New Component**: > - `PredictFeeBreakdownSheet`: Bottom sheet showing per-fee breakdown (`Polymarket fee`, `MetaMask fee`), `shouldNavigateBack=false`, `onClose` support. > - **Localization**: > - Add strings for `predict.fee_summary.fees`, `provider_fee_label`, `estimated_points`, points tooltips/error content. > - **Tests**: > - Add tests for `PredictFeeBreakdownSheet` and rewards/fees behavior; update existing expectations from "Provider fee" to "Fees". > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 01962c5. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
Adds the Tron network to swaps/bridge.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: added Tron network support in swaps
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds Tron support to swaps and bridge, filters non‑tradable Tron
tokens, updates fee/status handling, defaults, and dependencies.
>
> - **Bridge/Swaps Integration**
> - Allow `TrxScope.Mainnet` in swaps (`isSwapsAllowed`) and bridge
(`ALLOWED_BRIDGE_CHAIN_IDS`, network name map).
> - Add Tron default swap token (`USDT` TRC20) in
`default-swap-dest-tokens.ts` and BIP44 pairs.
> - **Token Handling**
> - New `isTradableToken` utility to exclude Tron resource tokens
(`Energy`, `Bandwidth`, `Max Bandwidth`).
> - `useTokens` now filters non‑tradable tokens, normalizes non‑EVM
addresses, and improves deduping/exclusions.
> - **UI/Logic**
> - `TransactionDetails`: safer multichain fee sum (handles partially
fungible fees) and unified status selection.
> - Asset utils: mark Solana/Tron assets as swaps‑allowed.
> - **Tests**
> - Extensive tests for non‑EVM normalization, Tron token filtering,
deduplication, and edge cases.
> - **Dependencies**
> - Bump `@metamask/bridge-controller` and
`@metamask/bridge-status-controller` to `^60.1.0`;
`@metamask/tron-wallet-snap` to `^1.7.x` (lockfile updated).
> - **Docs**
> - Minor README fixes (overlay usage, sample E2E notes).
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b88a55b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: GeorgeGkas <georgegkas@gmail.com>
…#22173) ## **Description** Removed `Text` component wrappers from `BottomSheetHeader` children across the codebase to ensure consistency with the new API pattern where `BottomSheetHeader` handles text styling internally. This refactoring removes redundant `Text` components that were wrapping string content inside `BottomSheetHeader`. The `BottomSheetHeader` component now handles the text styling directly, ensuring a consistent appearance across all bottom sheet headers in the app. ## **Changelog** CHANGELOG entry: null ## **Related issues** Part of: https://consensyssoftware.atlassian.net/browse/MDP-343 ## **Manual testing steps** ```gherkin Feature: Bottom Sheet Headers Display Correctly Scenario: user views various bottom sheets with headers Given the app is running When user opens any bottom sheet modal with a header (e.g., network selector, payment method selector, region selector, account permissions, etc.) Then the header text should display correctly with proper styling And the header should be visually consistent with other bottom sheet headers ``` ## **Screenshots/Recordings** ### **Before** N/A - Internal refactoring, no visual changes. We can trust the component to handle styling correctly. ### **After** N/A - Internal refactoring, no visual changes. We can trust the component to handle styling correctly. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- ### **Changes Summary** **11 component files updated:** - NetworkSettings/index.js (4 instances) - NetworkListBottomSheet.tsx - TooltipModal/index.tsx - AccountPermissionsConfirmRevokeAll.tsx - NetworkSelector/NetworkSelector.tsx - RpcSelectionModal/RpcSelectionModal.tsx - NetworkManager/index.tsx - PermittedNetworksInfoSheet.tsx - ConnectionDetails/ConnectionDetails.tsx - RegionSelectorModal/RegionSelectorModal.tsx - PaymentMethodSelectorModal.tsx **5 test snapshots updated:** - RegionSelectorModal (8 snapshots) - PaymentMethodSelectorModal (1 snapshot) - AccountPermissionsConfirmRevokeAll (1 snapshot) - ConnectionDetails (1 snapshot) - PermittedNetworksInfoSheet (1 snapshot) **Total:** 16 files changed, 54 insertions(+), 60 deletions(-) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Refactors BottomSheetHeader to take raw string children across modals/selectors and updates tests/snapshots and small header style expectations. > > - **UI/BottomSheetHeader refactor**: > - Replace `<Text>` wrappers with raw string children in `BottomSheetHeader` across: > - Bridge: `BlockaidModal`, `BridgeNetworkSelectorBase`, `BridgeTokenSelectorBase`, `QuoteExpiredModal`, `SlippageModal`, `TransactionDetails/BlockExplorersModal`. > - Ramp (Deposit): `PaymentMethodSelectorModal`, `RegionSelectorModal`. > - Account Permissions: `AccountPermissionsConfirmRevokeAll`, `ConnectionDetails`, `PermittedNetworksInfoSheet`. > - Networks: `NetworkManager`, `AddAsset/NetworkListBottomSheet`, `NetworkSelector`. > - Misc: `TooltipModal`. > - **Tests/Snapshots**: > - Update snapshots to new header structure: add `testID="header-title"`, center text, and expect fontSize 16. > - Adjust NetworkManager tests to assert `testID="header"` instead of mocked header ID; extend icon mocks. > - **Styles**: > - Remove unused `heading` style in `NetworkSettings` styles; align header typography via `BottomSheetHeader`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ddcd7e7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…mask pay deposits (#23309) - fix: cp-7.60.0 remove max button from metamask pay deposits (#23287) ## **Description** Replace the `Max` button in the Predict and Perps deposit confirmations with a `90%` button. Remove the target amount from the insufficient fees alert. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: #23265 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** <img width="300" alt="90" src="https://github.com/user-attachments/assets/23ce05c6-cd03-4052-b5e5-eae1d9115106" /> <img width="300" alt="Alert" src="https://github.com/user-attachments/assets/87c0f5da-2550-4b4d-98e9-bccda557c195" /> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Default deposit quick-action changes from Max to 90% (with optional hasMax to restore Max), and insufficient fees alerts no longer include a target amount; tests and wiring updated. > > - **Deposits UI**: > - `DepositKeyboard`: Replace `Max` with `90%` in default `PERCENTAGE_BUTTONS`; add `hasMax` prop to swap `90%` for `Max`; memoize `buttons`. > - `CustomAmountInfo`/`PredictWithdrawInfo`: Plumb `hasMax`; enable `hasMax` for Predict Withdraw. > - **Alerts**: > - `useInsufficientPayTokenBalanceAlert`: Remove target-amount calculation/fiat formatting; fees alert always uses `alert_system.insufficient_pay_token_balance_fees_no_target.message`. > - **Tests**: > - Update `deposit-keyboard` tests for `hasMax` and `90%` behavior. > - Simplify alert hook tests to expect no-target fees message and remove obsolete cases. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fa4a813. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [2b25287](2b25287) Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
add mon currency to the currencies list
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution? -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: add mon currency to currencies list
Fixes:
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
<!-- [screenshots/recordings] -->
<img width="457" height="900" alt="Screenshot 2025-11-25 at 18 47 45"
src="https://github.com/user-attachments/assets/64f9d752-da8b-44ea-978b-5ec8989c14c6"
/>
<!-- [screenshots/recordings] -->
- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Lower-cases account keys when storing token balances and adds 'mon' to
supported currencies.
>
> - **Balances**:
> - Normalize `account` to lower-case in
`dist/TokenBalancesController.(cjs|mjs)` when reading/writing
`d.tokenBalances`, preventing mixed-case keys.
> - **Prices**:
> - Add `"mon"` to `SUPPORTED_CURRENCIES` in
`dist/token-prices-service/codefi-v2.cjs`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3dba1e3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
…issue (#23307) - chore: fix signature verification sorting issue cp-7.60.0 (#23220) ## **Related issues** Fixes: #23222 - issue where URL canonicalization was not properly sorting due to the way that `.sort` works on React Native. - add case for `sig_params` being empty, so that we can still sign links without any parameters that need to be signed - removed edge case unit test since it added very little value (no one should be using spaces in a signed URL) ## **Description** **Reason for change:** Deep link signature verification was failing for marketing links (e.g., `https://link.metamask.io/perps?sig_params=...&utm_...`). The Mobile app's `canonicalize` function had diverged from the Extension's implementation, causing signature mismatches. The root cause: **React Native's `URLSearchParams.sort()` is not implemented** — it throws an error. This meant parameters weren't being sorted correctly, so the canonical URL didn't match what was signed. **Improvement/solution:** Updated the `canonicalize` function to: 1. **Use custom array sorting** instead of `URLSearchParams.sort()` (which is broken in React Native) 2. **Handle empty `sig_params` explicitly** — when `sig_params=''`, only include `sig_params` itself in the canonical URL (allows appending UTMs after signing) 3. **Use `getAll()`/`append()`** instead of `get()`/`set()` to preserve multiple values for the same parameter (matches Extension behavior) 4. **Use `encodeURIComponent()`** for consistent URL encoding These changes align Mobile with the Extension's canonicalization logic, ensuring signed deep links verify correctly. ## **Changelog** CHANGELOG entry: Fixed deep link signature verification failing for marketing links with UTM parameters ## **Manual testing steps** ```gherkin Feature: Deep Link Signature Verification Scenario: user opens a signed deep link with sig_params and appended UTMs Given a signed deep link with sig_params listing specific parameters And UTM parameters are appended after signing When user opens the deep link in the app Then the signature verifies successfully And the user is not shown the unsigned link warning modal Scenario: user opens a signed deep link with empty sig_params Given a signed deep link with sig_params= (empty) And UTM parameters are appended after signing When user opens the deep link in the app Then the signature verifies successfully And only sig_params is used for verification (UTMs ignored) Scenario: user opens a signed deep link without sig_params (legacy) Given a signed deep link without any sig_params parameter When user opens the deep link in the app Then all parameters (except sig) are included in verification And the signature verifies successfully (backward compatibility) ``` ## **Screenshots/Recordings** ### **Before** Signed marketing links showed the "unsigned link" warning modal due to signature verification failure. ### **After** Signed marketing links verify correctly and open without the warning modal. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- **Labels to add:** `team-mobile-platform` [65ae4f9](65ae4f9) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Revamps deep-link canonicalization to use custom param sorting, explicitly handle empty `sig_params`, and preserve multi-value params; updates tests accordingly. > > - **Deeplink verification utils (`app/core/DeeplinkManager/ParseManager/utils/verifySignature.ts`)**: > - **Canonicalization**: > - Replace `URLSearchParams.sort()` with custom key sorting and explicit encoding via `encodeURIComponent`. > - Handle `sig_params=''` by signing only `sig_params` itself (exclude other params). > - When `sig_params` present, include only listed params (via `getAll`/`append`) and append `sig_params`. > - Legacy path: without `sig_params`, include all params except `sig`. > - **Tests (`verifySignature.test.ts`)**: > - Add cases for deterministic alphabetical sorting and empty `sig_params` behavior. > - Expand coverage for multi-param/missing-param scenarios and legacy behavior. > - Remove low-value edge case test for spaces in `sig_params`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 310f03d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Kylan Hurt <6249205+smilingkylan@users.noreply.github.com>
… explorer urls on bridge txs (#23311) - fix: cp-7.60.0 Generate correct blockchain explorer urls on bridge txs (#23273) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Fix an issue where the blockchain explorer urls were not generated successfully when bridging assets. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Generate correct blockchain explorer URLs when bridging assets ## **Related issues** Fixes: #23171 ## **Manual testing steps** ```gherkin Ensure that the correct blockchain URLs are generated when visiting the transaction details screen after bridging/swapping assets. Also ensure that the correct URLs are also generated for old bridge/swaps transactions (no regressions). ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Fixes bridge transaction explorer URL generation across EVM and non‑EVM chains with proper fallbacks and updates tests accordingly. > > - **Bridge Hook (`useMultichainBlockExplorerTxUrl`)**: > - Switches to `useBlockExplorer` from `app/components/hooks` and uses `getEvmBlockExplorerUrl` to derive EVM explorer base URLs. > - Falls back to `getEtherscanBaseUrl` and builds links via `@metamask/etherscan-link` when custom explorer is unavailable. > - Determines explorer names via URL for non‑EVM and via `blockExplorer.getBlockExplorerName` for EVM. > - Keeps network image sourcing and chain name resolution, handling unknown networks gracefully. > - **Hook Tests** (`useMultichainBlockExplorerTxUrl.test.tsx`): > - Comprehensive coverage for parameter validation, EVM (mainnet, Optimism, Polygon) and non‑EVM (Solana) paths, fallbacks, explorer name resolution, network image sourcing, and edge cases. > - **Modal Test** (`BlockExplorersModal.test.tsx`): > - Updates expectations to one `Etherscan` and one `Optimistic` button. > - **Block Explorer Hook** (`useBlockExplorer.ts`): > - Exposes `getEvmBlockExplorerUrl` in returned API. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4b8a441. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [f93f627](f93f627) Co-authored-by: George Gkasdrogkas <georgegkas@gmail.com>
…23286) - fix: cp-7.60.0 predict withdraw using gas station (#23255) ## **Description** Fix Predict withdraw when using gas station with insufficient existing token balance. Bump `transaction-controller` and `transaction-pay-controller`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: #23137 #23126 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Skips adding gas-fee-token batch/7702 external sign when `txMeta.isGasFeeTokenIgnoredIfBalance` is true, adds tests, exposes remote feature flag to messengers, and bumps transaction-related dependencies. > > - **Confirmations**: > - Respect `txMeta.isGasFeeTokenIgnoredIfBalance` in `useTransactionConfirm` to avoid adding `batchTransactions` or setting `isExternalSign`. > - Add tests ensuring no `batchTransactions`/`isExternalSign` when gas fee token should be ignored. > - **Engine/Messaging**: > - Delegate `RemoteFeatureFlagController:getState` to transaction controller messengers. > - Minor typing adjustment around `getNetworkClientRegistry`. > - **Dependencies**: > - Bump `@metamask/transaction-controller` to `62.3.0` and `@metamask/transaction-pay-controller` to `10.1.0` (with related lockfile updates). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8f80ad1. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [69d1ae2](69d1ae2) --------- Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
…`:accountCreated` idempotency) cp-7.60.0 (#23326) - chore: bump `eth-snap-keyring` (to enable `:accountCreated` idempotency) cp-7.60.0 (#23310) ## **Description** Bumping `@metamask/eth-snap-keyring` to enable `notify:accountCreated` idempotency which is required by the Bitcoin Snap. This will reduce the number of "misaligned" warnings we had with Bitcoin. Similar to: - MetaMask/metamask-extension#38292 ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: - #23324 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Bumps `@metamask/eth-snap-keyring` to 18.0.2 and updates related keyring dependencies for alignment. > > - **Dependencies**: > - Bump `@metamask/eth-snap-keyring` to `^18.0.2` in `package.json` and `yarn.lock`. > - Align related keyring packages in `yarn.lock`: `@metamask/keyring-api` `^21.2.0`, `@metamask/keyring-internal-api` `^9.1.1`, `@metamask/keyring-internal-snap-client` `^8.0.1`, `@metamask/keyring-snap-client` `^8.1.1`, `@metamask/keyring-snap-sdk` `^7.1.1` (including peer dep updates). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b4dd0a7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [97fe703](97fe703) Co-authored-by: Charly Chevalier <charlyy.chevalier@gmail.com>
…hains cp-7.60.0 (#23334) - fix: update logic to support all non-evm chains cp-7.60.0 (#23328) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Update logic to include all non-evm chains when parsing deep link urls. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Update logic for deeplink parsing to take into account all non-EVM chains ## **Related issues** Fixes: #23314 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ x ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ x ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ x ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Generalizes asset metadata fetching to support all non-EVM chains by replacing Solana-specific logic with `isNonEvmChainId`. > > - **Bridge asset metadata utils (`app/components/UI/Bridge/hooks/useAssetMetadata/utils.ts`)**: > - Generalizes non-EVM handling in `fetchAssetMetadata` by replacing Solana-specific check with `isNonEvmChainId`. > - Imports `isNonEvmChainId` from `@metamask/bridge-controller` and updates non-EVM address extraction via `parseCaipAssetType`. > - Maintains existing EVM path (using `parseCaipChainId`, `formatAddressToCaipReference`, `formatChainIdToHex`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8bc891b. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [3cf4f74](3cf4f74) Co-authored-by: SteP-n-s <stylianos.panagakos@consensys.net>
…istered error detection in BasicInfo form (#23333) - fix(ramp): cp-7.60.0 fix phone already registered error detection in BasicInfo form (#23299) ## **Description** Fixed error handling in BasicInfo component to correctly access error codes from Axios error responses. The code was previously trying to access `error.error.errorCode` but Axios errors have the structure `error.response.data.error.errorCode`, which prevented error code 2020 (phone already registered) from being detected correctly. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: #23302 ## **Manual testing steps** ```gherkin Feature: BasicInfo form error handling Scenario: user submits form with already registered phone number Given I am on the BasicInfo screen with valid form data When I submit the form with a phone number that is already registered Then I should see an error message indicating the phone is already registered And I should see a "Log in with email" button And clicking the logout button should navigate to the email entry screen ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="333" height="720" alt="image" src="https://github.com/user-attachments/assets/0a01a7be-e4bb-496c-8396-e77d5785b668" /> ### **After** https://github.com/user-attachments/assets/e8acba92-1032-4f49-a5bd-84a605bda71f ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Fixes BasicInfo to read Transak error code 2020 from Axios responses, show a formatted email message with a logout action, and navigate to email entry; tests updated to use AxiosError. > > - **BasicInfo (`BasicInfo.tsx`)**: > - Parse Axios error via `response.data.error` to detect Transak `errorCode` `2020`. > - Extract email from error message and display localized "phone already registered" text. > - Toggle `isPhoneRegisteredError` to render a "Log in with email" action; on press, call `logoutFromProvider(false)` and navigate to `Routes.DEPOSIT.ENTER_EMAIL`. > - Preserve error visibility and log on logout failure; minor import of `AxiosError`. > - **Tests (`BasicInfo.test.tsx`)**: > - Update error mocks to use `AxiosError` with `response.data.error.errorCode` `2020`. > - Assert formatted message, presence/absence of logout button, logout flow navigation, and graceful handling of logout errors. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 46aa1dd. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [3807955](3807955) Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com>
…23331) - fix: cp-7.60.0 non-evm accounts not found (#23318) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Fix Non-EVM accounts not found Fixes part of this MetaMask/metamask-extension#38104 <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: fix: non-evm accounts not found ## **Related issues** Fixes: MetaMask/metamask-extension#38104 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Upgrade snaps dependencies in package.json: @metamask/solana-wallet-snap to ^2.5.0 and @metamask/tron-wallet-snap to ^1.13.0 (with lockfile updates). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b108def. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [ec74886](ec74886) Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
Allows machines with small amount of logical cpu core count
to run Metro worker code concurrently
For example, previous value would force GH runners to run worker code
in the main Metro process.
This was causing Metro bundler processes to crash due to JS heap
memory limit being exhausted
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
|
|
@SocketSecurity ignore npm/@metamask/transaction-pay-controller@10.1.0 |
…#23375) - fix: fix recipient account icons cp-7.60.0 (#23362) ## **Description** The icon being used for each recipient addresses was not re-using their account group icons (we use the EVM address of a multichain account group as the seed of account's icons). This PR fixes this while keeping the original `recipient.address` as a fallback (which should never happen anyway). ## **Changelog** CHANGELOG entry: Fix account's icons for send flows ## **Related issues** Fixes: - #22806 ## **Manual testing steps** ```gherkin Feature: Send non-EVM token Scenario: user starts a send flow for Solana Given the user has funds When user selects the recipient address Then he should see the same icons than the one used for the account list ``` ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/100969c2-15e9-49c4-a2f3-cd24aac8e839 <img width="382" height="192" alt="Screenshot 2025-11-27 at 13 28 36" src="https://github.com/user-attachments/assets/53225dd9-8e47-4788-850e-09579c312e96" /> <img width="377" height="250" alt="Screenshot 2025-11-27 at 13 28 22" src="https://github.com/user-attachments/assets/07e5b9aa-4a1c-44ff-ac6a-402a0712bd1a" /> ### **After** https://github.com/user-attachments/assets/221c05e4-b040-4583-b81f-de674f716db1 <img width="385" height="220" alt="Screenshot 2025-11-27 at 13 29 52" src="https://github.com/user-attachments/assets/02b959f4-7334-454f-8939-931054f68bf3" /> <img width="383" height="194" alt="Screenshot 2025-11-27 at 13 29 36" src="https://github.com/user-attachments/assets/a1eb109d-e74a-4de2-9844-ec5675e565c3" /> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Recipient avatars now use the account group’s icon seed with address fallback; useAccounts adds accountGroupId and tests updated accordingly. > > - **Confirmations UI**: > - `app/components/Views/confirmations/components/UI/recipient/recipient.tsx` > - Avatar `accountAddress` now sourced from account group seed via `selectIconSeedAddressByAccountGroupId(recipient.accountGroupId)` with fallback to `recipient.address`. > - Adds Redux selector usage and `AccountGroupId` typing. > - **Send Hooks**: > - `app/components/Views/confirmations/hooks/send/useAccounts.ts` > - Includes `accountGroupId` in returned recipient objects. > - **Tests**: > - `useAccounts.test.ts` expectations updated to include `accountGroupId` across EVM, Solana, Bitcoin, and Tron cases. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f41df4d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [0f7ac87](0f7ac87) Co-authored-by: Charly Chevalier <charlyy.chevalier@gmail.com>
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsAnalysis SummaryI've analyzed 100 changed files across the codebase. The changes span multiple areas with varying levels of criticality: Major Change Categories:
Risk Assessment:Medium Risk because:
Tag Selection Rationale:
Not Selected:
Confidence: 75%Moderate-high confidence based on:
|



🚀 v7.60.0 Testing & Release Quality Process
Hi Team,
As part of our new MetaMask Release Quality Process, here’s a quick overview of the key processes, testing strategies, and milestones to ensure a smooth and high-quality deployment.
📋 Key Processes
Testing Strategy
Conduct regression and exploratory testing for your functional areas, including automated and manual tests for critical workflows.
Focus on exploratory testing across the wallet, prioritize high-impact areas, and triage any Sentry errors found during testing.
Validate new functionalities and provide feedback to support release monitoring.
GitHub Signoff
Issue Resolution
Cherry-Picking Criteria
🗓️ Timeline and Milestones
✅ Signoff Checklist
Each team is responsible for signing off via GitHub. Use the checkbox below to track signoff completion:
Team sign-off checklist
This process is a major step forward in ensuring release stability and quality. Let’s stay aligned and make this release a success! 🚀
Feel free to reach out if you have questions or need clarification.
Many thanks in advance
Reference